How do I store this data in Java? - java

I want a dictionary of values. The keys are all strings. Each key corresponds with some sort of list of strings. How do I make a list of strings for each key and update that accordingly? I'll explain:
I have a loop that is reading lines of a word list. The words are then converted into a string code and set as keys in the dictionary. Here is an example of the string code/word relationship.
123, [the]
456, [dog]
328, [bug]
...
However, my program keeps looping through the word list and eventually will run into a word with the same code as "the", but maybe a different word, lets say "cat". So I want the list to look like:
123, [the, cat]
456, [dog]
...
How do I get it to make an arraylist for every key that I can then add to on the fly when needed? My end goal is to be able to print out the list of words in that list for a called code (.get())

You can make a HashMap. In your case
HashMap<Integer, ArrayList<String>> works fine.

Like it has already been said, a MultiMap seems to be what you need. Guava that was already suggested and it's a good option. There is also and implementation from commons-collections you can use.
From commons-collections documentation:
MultiValuedMap<K, String> map = new MultiValuedHashMap<K, String>();
map.put(key, "A");
map.put(key, "B");
map.put(key, "C");
Collection<String> coll = map.get(key); // returns ["A", "B", "C"]
You can always implement your own MultiMap if you don't want to use an external library. Use a HashMap<String,List<String>> to store your values and wrap it with your own put, get and whatever other methods you see fit.

It sounds like you want a Multimap from the Guava library.
You can also go the route of using a Map<Integer, List<String>>, but then you will need to manually handle the case where the list is null (probably just allocate a new list in that case).

You can use a HashMap that links each id to a list of strings:
Map<String, List<String>> dictionary = new HashMap<String,List<String>>();
Now let's say you read two Strings: id and word . To add them to your dictionary, you can first verify if your id has already been read (using the containsKey() method)- in which case you just append the word to the list corresponding to that id - or, if this is not the case, you create a new list with this word:
//If the list already exists...
if(dictionary.containsKey(id)) {
List<String> appended = dictionary.get(id);
appended.add(word); //We add a new word to our current list
dictionary.remove(id); //We update the map by first removing the old list
dictionary.put(id, appended); //and then appending the new one
} else {
//Otherwise we create a new list for that id
List<String> newList = new ArrayList<String>();
newList.add(word);
dictionary.put(id, newList);
}
Then whenever you want to retrieve your list of strings for a certain id you can simply use dictionary.get(id);
You can find more information on HashMaps on the Java documentation

I assumed you didn't want repeats in your list so I used Set instead.
Map<String,Set<String>> mapToSet = new HashMap<>();
List<String []>keyvals = Arrays.asList(new String[][]{{"123","the"},{"123","cat"}});
for(String kv[] : keyvals) {
Set<String> s = mapToSet.get(kv[0]);
if(null == s) {
s = new HashSet<String>();
}
s.add(kv[1]);
mapToSet.put(kv[0], s);
}

Related

Create multiple Lists from one (Group List's Objects by a specific field)

Given that I have the array of :
List<CustEnt> bulkList= CustRepo.fetchData();
//System.out.println(bulkList) -->
gives me :
CustEct(name:"kasis",age:24,surname:"kumar"),CustEct(name:"samika",age:50,surname:"sharma"),CustEct(name:"manoj",age:84surname:"kumar")
OR
bulkList.get(1) --> CustEct(name:"kasis",age:24,surname:"kumar")
I want to create a new array which is grouped by the 3rd parameter of surname object.
So that my array becomes
ArrayFinal = [CustEct(name:"kasis",age:24,surname:"kumar"),CustEct(name:"samika",age:50,surname:"sharma")],CustEct(name:"manoj",age:84surname:"kumar")
So that when we do .get(1) we would get object of kasis and samika.
Need the help in respective to java 8.
I heard that we can use the Map ,but can anyone give the small code sample or any other implementation guide.
A Map tracks key-value pairs.
Your key is the surname string.
Your value is a list of the CustEnt objects carrying that surname.
Map<String, List<CustEnt>>
Modern syntax with streams and lambdas makes for brief code to place your objects in a map.
Something like:
Map<String, List<CustEnt>> map = originalList.stream.collect(Collectors.groupingBy(CustEnt::getSurename));
Map<String, List<CustEntity>> NamesList
= bulkList.stream()
.collect(Collectors.groupingBy(CustEntity::getSurames));
for (Map.Entry<String, List<CustEntity>> entry: NamesList.entrySet()) {
ExcelGenerationService exp = new ExcelGenerationService( entry.getValue());
//service call
exp.export(entry.getKey());
}

Pull out the a spefic "rank" from an HashMap not yet sorted which also contains different values but same key or better same count;

I have this HashMap containing words and the count for each word from a given text file;
{word=1, word2=1, word3=2, word4=1, word5=1, word6=4, word7=1, word8=1};
i was following your suggestion in other topics; but i have notice that if use fro example sorted Collections and i search for a specific KEY which could be 1 in this case it only return me one word while instead can return more values for same key;
the point is between all the collections:
Lists
Maps
ArrayLists
Trees
HashMaps
HashTables
which is the most advisable to use?
on my Class the user will input an int and that int will correspond to the 1st or 2nd or 3rd or 4th and so on..... words used in the files base on the count and occurences;
it's challenging
so far i have managed to store in hashmap and eventually order it in a Tree by Desc Key; so first element will be the greater; but still the algorithm needs more sense;
ps. i do not expect solution or pieces of codes but a good input to start ... a very good advise or direction best to follow;
Maps, by nature, store (will return) only one element per key. That means that if you'll store [key:1, val:a] and then store again [key:1, val:2]. The second insertion will override the first and when you'll "get" key:1 the returned result will be b.
You can, however, to store a List per key. This list can store all the value values per the same key.
So we'll declare the map that we'l use as follows:
Map<String, LinkedList<String>> map = new HashMap<>();
This is how insert should look like:
public void insert(String key, String value){
List<String> values = map.get(key);
if (values == null){ // this is the first time we use this key
values = new LinkedList<String>(); // so we need to create a new values List
}
values.add(value);
map.put(key, values)
}
the "get" is pretty straightforward:you get the list of values and if it's not null - iterate the values and print/do whatever you want with them.
public List<String> get(String key){
return map.get(key);
}
If I understand you correctly, you have a Map<String,Integer> map; which maps words to their frequencies, and now you want to look up words by frequency.
Create a new map that Map<Integer,List<String>> and fill it using the first map:
Map<Integer,List<String>> reverseMap = new HashMap<>();
for (Map.Entry<String,Integer> entry : map.entrySet()) {
List<String> list = reverseMap.get(entry.getValue());
if (list == null) {
reverseMap.put(entry.getValue(), list = new ArrayList<>());
}
list.add(entry.getKey());
}
You will get a map like:
java.util.HashMap[3] {
1=[word2, word4, word, word5, word7, word8]
2=[word3]
4=[word6]
}
In this map, each key is the frequency, each value is a list of words having that frequency.
Edit: To pull out the words having the second-most used frequency ("rank 2"), generate a list of the most used frequencies:
List<Integer> frequencies = new ArrayList<>(reverseMap.keySet());
Collections.sort(frequencies, Collections.reverseOrder());
Then:
System.out.println(reverseMap.get(frequences.get(2 - 1)));
Or, to sort the entire map in descending order of frequency (4, 2, 1), declare it as a TreeMap instead of a HashMap, with a reverseOrder comparator:
Map<Integer,List<String>> reverseMap = new TreeMap<>(Collections.reverseOrder());

Looping to enter values into Java Hashmap

i am trying to insert values into a hashmap. I have it in a loop as the values are being retrieved from a list of strings. The code is as follows:
HashMap<String, String> resultHashMap = new HashMap<String, String>();
//add the top document id back to the resultHashMap
resultHashMap.put("entryObject", dsStepParam.getValue());
for(String res : results)
{
log.info(res);
resultHashMap.put("dataObject", res);
}
The hashMap (after this loop should contain the following:
{"entryObject":"500386787",
"dataObject":"500386883;500901929",
"dataObject":"500386906;500901969",
"dataObject":"500386787;500901666",
"dataObject":"500386784;500901654",
"dataObject":"500386762;500901599"}
however the actual contents are:
{"entryObject":"500386787",
"dataObject":"500386762;500901599"}
As you can see it only stores the entryObject and the last dataObject.
How can I make it store all the values in the hashMap?
It only stores the last entry because duplicate keys are not allowed in a hashmap. To store all elements you could do something like this
int count = 0;
for(String res : results)
{
log.info(res);
resultHashMap.put("dataObject-"+count, res);
count++;
}
Thus you'd get something like this
{"entryObject":"500386787",
"dataObject-1":"500386883;500901929",
"dataObject-2":"500386906;500901969",
"dataObject-3":"500386787;500901666",
"dataObject-4":"500386784;500901654",
"dataObject-5":"500386762;500901599"}
If you want it to store all values in the hashMap you need to allow duplicates in the map. For this to happen, you'd need to use Google's version of Multimap, which can be found here
The keys in hashMap are unique so you are seeing the last entry for the duplicate keys inserts. If you want to store multiple items associated to one key then you can make use MultiMap i.e a map that holds a collection of values against each key. Couple of good multimap implementations are available:
Apache MultiMap
Guava MultiMap

while loop inside for loop not working

I have a HashMap.
Map<String,String> lhm = new HashMap<String,String>();
lhm.put("Zara", "biu");
lhm.put("Mahnaz", "nuios");
lhm.put("Ayan", "sdfe");
lhm.put("Daisy", "dfdfh");
lhm.put("Qadir", "qwe");
I want to sort that hashmap according to the sequence which is given in properties file.Actually that property entry will be having the keys in some order.My property entry will looks like this
seq=Ayan,Zara,Mahnaz,Qadir,Daisy
What I have tried towards this is
Map<String,String> lhm = new HashMap<String,String>();
Properties prop=new Properties();
prop.load(new FileInputStream("D:\\vignesh\\sample.properties"));
// Put elements to the map
lhm.put("Zara", "biu");
lhm.put("Mahnaz", "nuios");
lhm.put("Ayan", "sdfe");
lhm.put("Daisy", "dfdfh");
lhm.put("Qadir", "qwe");
// Get a set of the entries
Set<Entry<String, String>> set = lhm.entrySet();
// Get an iterator
Iterator<Entry<String, String>> iter = set.iterator();
// Display elements
String sequence=prop.getProperty("seq");
System.out.println("sequence got here is "+sequence);
String[] resultSequence=sequence.split(",");
for(int j=0;j<resultSequence.length;j++)
{
while(iter.hasNext()) {
Map.Entry me = (Map.Entry)iter.next();
String res=(String) me.getKey();
if(res.equals(resultSequence[j]))
{
System.out.println("values according with the sequence is "+lhm.get(resultSequence[j]));
}
}
}
The output which I'm getting after this is
sequence got here is Ayan,Zara,Mahnaz,Qadir,Daisy
values according with the sequence is sdfe
My expected output is
values according with the sequence is sdfe
values according with the sequence is biu
values according with the sequence is nuios
values according with the sequence is qwe
values according with the sequence is dfdfh
It is working for the first iteration in my for loop.After that it exits from my for loop also.What I'm missing here??Thanks for reading.
It's not working because you never reset your iterator. You only match the string on your first run. Try putting the iterator inside the loop, to get a new one for every iteration, like this:
for(int j=0;j<resultSequence.length;j++)
{
Iterator<Entry<String, String>> iter = set.iterator();
while(iter.hasNext()) {
....
}
}
You are complicating your task too much. In fact, you are just printing your values in sorted order, but not actually sorting them. Also, that's a pathetic way to implement sorting. You are iterating over your map as much number of times as there are strings in your sequence (Currently it's 5).
You should use a TreeMap instead, if you want to sort your keys. Here, you will need to pass custom Comparator, which will compare based on value in your property file.
Suppose you have order in a string:
String order = "Ayan,Zara,Mahnaz,Qadir,Daisy";
then your comparator would look like:
Comparator<String> comparator = new Comparator<String>() {
#Override
public int compare(String key1, String key2) {
return order.indexOf(key1) - order.indexOf(key2);
}
};
The comparator compares each key in the TreeMap based on it's index in the order string.
Now just pass this comparator to the overloaded TreeMap constructor.
SortedMap<String,String> lhm = new TreeMap<String,String>(comparator);
Now, whatever you insert in the map, will be sorted according to the order defined in property file.
To iterate over the map, you can use enhanced for loop:
for(Entry<String, String> entry : lhm.entrySet()) {
System.out.println(entry.getValue());
}
You should get iterator for each iteration of for loop:
...
for(int j=0;j<resultSequence.length;j++)
{
// Get an iterator
Iterator<Entry<String, String>> iter = set.iterator();
while(iter.hasNext()) {
...
Use a TreeMap. This allows you to write a custom comparator for sorting the entries.
HashMap does not save any order, I think you should use LinkedHashMap that iterates in same order that values were inserted.
I think that you don't need iterate with the while loop, once you get the ordered array with the keys from the properties file is enough to do this:
for (String key:resultSequence) {
String value = lhm.get(key);
System.out.println("values according with the sequence is "+ value);
}
Iterate over the keys of your property file. For each of them, get the element in your map, if it exists.
Your while loop only get executed only once , because the iterator doesn't hold any more values after it reached the last element . Instead of while iterator use
for each loop Or else create a new iterator inside for loop and try
Well as the other answers have shown your error which is not reseting the iterator, let me propose another way of doing what you are trying to achieve.
If you want to go through the entire list, intead of using an iterator and writing the usual while(iter.hasNext()){} loop you may want to consider using a for loop as in the following example :
Map<String,String> lhm = new HashMap<String,String>();
// Put elements to the map
lhm.put("Zara", "biu");
lhm.put("Mahnaz", "nuios");
lhm.put("Ayan", "sdfe");
lhm.put("Daisy", "dfdfh");
lhm.put("Qadir", "qwe");
for(Entry<String, String> e : lhm.entrySet()) {
// do something as the for loop iterates through your map.
// e being the current element.
}

Searching through Collections in Java

I have a java properties file containing a key/value pair of country names and codes. I will load the contents of this file into a Collection like List or HashMap.
Then, I want users to be able to search for a country, e.g if they type 'Aus' in a textbox and click submit, then I want to search through the collection I have, containing a key/value pair of country codes/names (e.g AUS=>Australia), and return those countries which are found matching.
Is there any more efficient way of doing this, other than looping through the elements of the collection and using charAt()?
If performance is important, you can use a TreeSet or TreeMap to hold the country names, and do the following can be used to identify countries that start with a given string.
NavigableMap<String, String> countries = new TreeMap<String, String>();
countries.put("australia", "Australia");
...
String userText = ...
String tmp = userText.toLower();
List<String> hits = new ArrayList<String>();
Map.Entry<String, String> entry = countries.ceilingEntry(tmp);
while (entry != null && entry.getKey().startsWith(tmp)) {
hits.add(entry.getValue());
entry = map.higherEntry(entry.getKey());
}
// hits now contains all country names starting with the value of `userText`,
// ignoring differences in letter case.
This is O(logN) where N is the number of countries. By contrast a linear search of a collection is O(N)
Looping with String.contains() is the way unless you want to move in some heavy artillery like Lucene.
Short of indexing the collection via something like Lucene, then you'd have to manually check by looping through all of the elements. You could use startsWith as opposed to looping over the string:
String userText = ...
for (Map.Entry<String, String> entry : map) {
boolean entryMatches = entry.getKey().startsWith(userText);
...
Or alternatively use regular expressions:
Pattern pattern = Pattern.compile(userText);
for (Map.Entry<String, String> entry : map) {
boolean entryMatches = pattern.matcher(entry.getKey()).find();
...
Since the list is small enough to load into memory, sort it and then do a binary search, using the static method java.util.Collections.binarySearch(). This returns an index, and works regardless of whether the exact string is in the list or not (although if it's not it returns a negative number, so be sure to check that). Then, starting from that index, just iterative forward to find all the strings with that prefix. As a nice side-effect, the resulting output will be in alphabetical order.
To make the whole thing case insensitive, remember to convert to lowercase when loading the list and of course convert the prefix to lowercase before searching.

Categories

Resources