Adding multiple values to one key in a HashMap - java

I am working on a project where I will be given two files; one with jumbled up words and the other with real words. I then need to print out the list of jumbled up words in alphabetical order with its matching real word(s) next to it. The catch is that there can be multiple real words per jumbled up word.
For example:
cta cat
ezrba zebra
psot post stop
I completed the program without accounting for the multiple words per jumbled up words, so in my HashMap I had to change < String , String > to < String , List < String > >, but after doing this I ran into some errors in the .get and .put methods. How can I get multiple words stored per key for each jumbled up word? Thank you for your help.
My code is below:
import java.io.*;
import java.util.*;
public class Project5
{
public static void main (String[] args) throws Exception
{
BufferedReader dictionaryList = new BufferedReader( new FileReader( args[0] ) );
BufferedReader scrambleList = new BufferedReader( new FileReader( args[1] ) );
HashMap<String, List<String>> dWordMap = new HashMap<String, List<String>>();
ArrayList<String> scrambled = new ArrayList<String>();
while (dictionaryList.ready())
{
String word = dictionaryList.readLine();
//throw in an if statement to account for multiple words
dWordMap.put(createKey(word), word);
}
dictionaryList.close();
ArrayList<String> scrambledList = new ArrayList<String>();
while (scrambleList.ready())
{
String scrambledWord = scrambleList.readLine();
scrambledList.add(scrambledWord);
}
scrambleList.close();
Collections.sort(scrambledList);
for (String words : scrambledList)
{
String dictionaryWord = dWordMap.get(createKey(words));
System.out.println(words + " " + dictionaryWord);
}
}
private static String createKey(String word)
{
char[] characterWord = word.toCharArray();
Arrays.sort(characterWord);
return new String(characterWord);
}
}

you could do something like :
replace the line:
dWordMap.put(createKey(word), word);
with:
String key = createKey(word);
List<String> scrambled = dWordMap.get(key);
//make sure that scrambled words list is initialized in the map for the sorted key.
if(scrambled == null){
scrambled = new ArrayList<String>();
dWordMap.put(key, scrambled);
}
//add the word to the list
scrambled.add(word);

dWordMap.put(createKey(word), word);
The dwordMap is of type HashMap>. So instead of word i.e. String it should be List.

Related

In Java, how do you loop through a string and check if it contains the keys in a hash map?

The goal is to write a text message abbreviation expander program that takes a string and checks for common abbreviations like LOL, IDK, etc. and replace them with the full length sentence, laugh out loud, I don't know, etc.
import java.util.HashMap;
import java.util.Scanner;
public class TextMsgExpander {
public static void main(String[] args) {
Scanner scnr = new Scanner(System.in);
System.out.println("Enter text: ");
String userInput = scnr.nextLine();
System.out.println("You entered: " + userInput);
// Create new instance of Hash Map
HashMap<String, String> map = new HashMap<String, String>();
//Key value pairs
map.put("LOL", "laugh out loud");
map.put("IDK", "I don't know");
map.put("BFF", "best friend forever");
map.put("TTYL", "talk to you later");
map.put("JK", "just kidding");
map.put("TMI", "too much information");
map.put("IMHO", "in my humble opinion");
//Access points
String LOL = map.get("LOL");
String IDK = map.get("IDK");
String BFF = map.get("BFF");
String TTYL = map.get("TTYL");
String JK = map.get("JK");
String TMI = map.get("TMI");
String IMHO = map.get("IMHO");
System.out.println(TMI);
// While user input contains any of the keys, replace keys with
// values.
return;
}
}
You can instead iterate(loop) over the complete set of keys and look for them in the userInput, if they are present replace them with the respective value from the map as :
for (Map.Entry<String, String> entry : map.entrySet()) {
if (userInput.contains(entry.getKey())) {
userInput = userInput.replaceAll(entry.getKey(), entry.getValue());
}
}
System.out.println("Converted string - " + userInput);

How to select random text value from specific row using java

I have three input fields.
First Name
Last item
Date Of Birth
I would like to get random data for each input from a property file.
This is how the property file looks. Field name and = should be ignored.
- First Name= Robert, Brian, Shawn, Bay, John, Paul
- Last Name= Jerry, Adam ,Lu , Eric
- Date of Birth= 01/12/12,12/10/12,1/2/17
Example: For First Name: File should randomly select one name from the following names
Robert, Brian, Shawn, Bay, John, Paul
Also I need to ignore anything before =
FileInputStream objfile = new FileInputStream(System.getProperty("user.dir "+path);
in = new BufferedReader(new InputStreamReader(objfile ));
String line = in.readLine();
while (line != null && !line.trim().isEmpty()) {
String eachRecord[]=line.trim().split(",");
Random rand = new Random();
//I need to pick first name randomly from the file from row 1.
send(firstName,(eachRecord[0]));
If you know that you're always going to have just those 3 lines in your property file I would get put each into a map with an index as the key then randomly generate a key in the range of the map.
// your code here to read the file in
HashMap<String, String> firstNameMap = new HashMap<String, String>();
HashMap<String, String> lastNameMap = new HashMap<String, String>();
HashMap<String, String> dobMap = new HashMap<String, String>();
String line;
while (line = in.readLine() != null) {
String[] parts = line.split("=");
if(parts[0].equals("First Name")) {
String[] values = lineParts[1].split(",");
for (int i = 0; i < values.length; ++i) {
firstNameMap.put(i, values[i]);
}
}
else if(parts[0].equals("Last Name")) {
// do the same as FN but for lastnamemap
}
else if(parts[0].equals("Date of Birth") {
// do the same as FN but for dobmap
}
}
// Now you can use the length of the map and a random number to get a value
// first name for instance:
int randomNum = ThreadLocalRandom.current().nextInt(0, firstNameMap.size(0 + 1);
System.out.println("First Name: " + firstNameMap.get(randomNum));
// and you would do the same for the other fields
The code can easily be refactored with some helper methods to make it cleaner, we'll leave that as a HW assignment :)
This way you have a cache of all your values that you can call at anytime and get a random value. I realize this isn't the most optimum solution having nested loops and 3 different maps but if your input file only contains 3 lines and you're not expecting to have millions of inputs it should be just fine.
Haven't programmed stuff like this in a long time.
Feel free to test it, and let me know if it works.
The result of this code should be a HashMap object called values
You can then get the specific fields you want from it, using get(field_name)
For example - values.get("First Name"). Make sure to use to correct case, because "first name" won't work.
If you want it all to be lower case, you can just add .toLowerCase() at the end of the line that puts the field and value into the HashMap
import java.lang.Math;
import java.util.HashMap;
public class Test
{
// arguments are passed using the text field below this editor
public static void main(String[] args)
{
// set the value of "in" here, so you actually read from it
HashMap<String, String> values = new HashMap<String, String>();
String line;
while (((line = in.readLine()) != null) && !line.trim().isEmpty()) {
if(!line.contains("=")) {
continue;
}
String[] lineParts = line.split("=");
String[] eachRecord = lineParts[1].split(",");
System.out.println("adding value of field type = " + lineParts[0].trim());
// now add the mapping to the values HashMap - values[field_name] = random_field_value
values.put(lineParts[0].trim(), eachRecord[(int) (Math.random() * eachRecord.length)].trim());
}
System.out.println("First Name = " + values.get("First Name"));
System.out.println("Last Name = " + values.get("Last Name"));
System.out.println("Date of Birth = " + values.get("Date of Birth"));
}
}

Reading and matching contents of two big files

I have two files each having the same format with approximately 100,000 lines. For each line in file one I am extracting the second component or column and if I find a match in the second column of second file, I extract their third components and combine them, store or output it.
Though my implementation works but the programs runs extremely slow, it takes more than an hour to iterate over the files, compare and output all the results.
I am reading and storing the data of both files in ArrayList then iterate over those list and do the comparison. Below is my code, is there any performance related glitch or its just normal for such an operation.
Note : I was using String.split() but I understand form other post that StringTokenizer is faster.
public ArrayList<String> match(String file1, String file2) throws IOException{
ArrayList<String> finalOut = new ArrayList<>();
try {
ArrayList<String> data = readGenreDataIntoMemory(file1);
ArrayList<String> data1 = readGenreDataIntoMemory(file2);
StringTokenizer st = null;
for(String line : data){
HashSet<String> genres = new HashSet<>();
boolean sameMovie = false;
String movie2 = "";
st = new StringTokenizer(line, "|");
//String line[] = fline.split("\\|");
String ratingInfo = st.nextToken();
String movie1 = st.nextToken();
String genreInfo = st.nextToken();
if(!genreInfo.equals("null")){
for(String s : genreInfo.split(",")){
genres.add(s);
}
}
StringTokenizer st1 = null;
for(String line1 : data1){
st1 = new StringTokenizer(line1, "|");
st1.nextToken();
movie2 = st1.nextToken();
String genreInfo2= st1.nextToken();
//If the movie name are similar then they should have the same genre
//Update their genres to be the same
if(!genreInfo2.equals("null") && movie1.equals(movie2)){
for(String s : genreInfo2.split(",")){
genres.add(s);
}
sameMovie = true;
break;
}
}
if(sameMovie){
finalOut.add(ratingInfo+""+movieName+""+genres.toString()+"\n");
}else if(sameMovie == false){
finalOut.add(line);
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return finalOut;
}
I would use the Streams API
String file1 = "files1.txt";
String file2 = "files2.txt";
// get all the lines by movie name for each file.
Map<String, List<String[]>> map = Stream.of(Files.lines(Paths.get(file1)),
Files.lines(Paths.get(file2)))
.flatMap(p -> p)
.parallel()
.map(s -> s.split("[|]", 3))
.collect(Collectors.groupingByConcurrent(sa -> sa[1], Collectors.toList()));
// merge all the genres for each movie.
map.forEach((movie, lines) -> {
Set<String> genres = lines.stream()
.flatMap(l -> Stream.of(l[2].split(",")))
.collect(Collectors.toSet());
System.out.println("movie: " + movie + " genres: " + genres);
});
This has the advantage of being O(n) instead of O(n^2) and it's multi-threaded.
Do a hash join.
As of now you are doing an outer loop join which is O(n^2), the hash join will be amortized O(n)
Put the contents of each file in a hash map, with key the field you want (second field).
Map<String,String> map1 = new HashMap<>();
// build the map from file1
Then do the hash join
for(String key1 : map1.keySet()){
if(map2.containsKey(key1)){
// do your thing you found the match
}
}

Correct usage of Hashmaps for synonyms

I am trying to store synonyms of a given word into a HashMap. I then take the user input and check to see if it is a word or its synonym. For example, suppose the main word is "bank" and its synonmyns are "safe","tresury" and "credit union". If the user enters "bank", I want to output the word "bank". If the user enters " safe", I still want to output the word "bank" because "safe" is a synonym of "bank".
Here is my Synonymn method
public static void populateSynonymMap() {
HashMap<String, String[]> synonymMap = new HashMap<String, String[]>();
String word = "bank";
String synonymn[] = { "safe", "treasury", "credit union" };
synonymMap.put(word, synonymn);
}
and here is my main method
public static void main(String args[]) throws ParseException, IOException {
/* Initialization */
List<String> matches = new ArrayList<String>();
HashMap<String, String[]> synonymMap = new HashMap<String, String[]>();
synonmynMap = populateSynonymMap(); //populate the map
boolean found = false;
Scanner in = new Scanner(System.in);
Scanner scanner = new Scanner(System.in);
String input = null;
System.out.println("Welcome To Artifical Intelligence DataBase ");
System.out.println("What would you like to know?");
System.out.print("> ");
input = scanner.nextLine().toLowerCase();
}
Your synonymMap should be organised other way arround, the key are the "synonyms" and the value is their common output.
So in your example:
String word = "bank";
String synonymn[] = { "safe", "treasury", "credit union" };
for (String syn : synonymn)
synonymMap.put(syn, word);
Then when user enters a word you check if it exists in the synonymMap and if so you return its value:
String syn = synonynMap.get(input);
if (syn != null) return syn;
else return input;
you can add every word of your synonym[] as key to your map too. of course with an array of synonyms containing the word and all other synonyms. i know there have to be better approaches, but thats the easiest way i can think of at the moment

How to get original codes from generated pattern in java?

Suppose I have java.util.Set<String> of "200Y2Z", "20012Y", "200829", "200T2K" which follows the same pattern "200$2$", where "$" is the placeholder. Now which is the most efficient way to get Set of just unique codes from such strings in Java?
Input: java.util.Set<String> of "200Y2Z", "20012Y", "200829", "200T2K"
Expected output: java.util.Set<String> of "YZ", "1Y", "89", "TK"
My Try ::
public static void getOutPut()
{
Set<String> input = new HashSet<String>();
Set<String> output = new HashSet<String>();
StringBuffer out = null;
for(String in : input)
{
out = new StringBuffer();
StringCharacterIterator sci = new StringCharacterIterator(in);
while (sci.current( ) != StringCharacterIterator.DONE){
if (sci.current( ) == '$')
{
out.append(in.charAt(sci.getIndex()));
}
sci.next( );
}
output.add(out.toString());
}
System.out.println(output);
}
It is working fine, but is there any efficient way than this to achieve it? I need to do it for more than 1000K codes.
Get the indexes of the placeholder in the pattern:
int i = pattern.getIndexOf('$');
You'll must to iterate to obtain all the indexes:
pattern.getIndexOf('$', lastIndex+1);
The loop and the checks are up to you.
Then use charAt with the indexes over each element of the set.

Categories