Store in a map a key with multiple values - java

I want to store in a map keys with multiple values.
For example : i am reading from an ArrayList the keys which are Strings and from another ArrayList the values which are integers:
Keys Values
humans 50
elfs 20
dwarfs 30
humans 40
elfs 10
and i want to store these informations like this: Map < String, ArrayList < Integer>>
[humans = {50,40}]
[elfs = {20,10}]
[dwarfs = {30}]
It is there possible to do this?

I recommend using the Guava MultiMap. Alternatively, your
Map<String, ArrayList<Integer>>
will also accomplish this. When doing a put, determine if there is already a list associated with the key; if there is then your put will be a get(key).add(value), otherwise it will be a put(new List(value)). Likewise a remove will remove a value from the associated list, or else will completely remove the list if this will result in an empty list.
Also, a Map<String, HashSet<Integer>> will probably result in better performance than a map of lists; obviously don't do this if you want to associate duplicate values with a key.

I do this:
public class StringToListInt {
private Map<String, List<Integer>> stringToListInt;
public StringToListInt() {
stringToListInt = new HashMap<String, List<Integer>>();
}
public void addInt( String string, Integer someValue ) {
List<Integer> listInt = stringToListInt.get( string );
if ( listInt == null ) {
listInt = new ArrayList<String>();
stringToListInt.put( string, listInt );
}
listInt.add( someValue );
}
public List<Integer> getInts( String string ) {
return stringToListInt.get( string );
}
}
If you add in some Generics, I imagine you would end up with something very similar to Guava's MultiMap without the dependency.

Related

Java Using Multiple predicate for anyMatch

I am having a List of HashMap i.e List<Map<String, Object>> result. I want to check if some key value is present on this list or not.
For Example:
Name Count
Marvel 10
DC 0
I want that my list of map should contain at least one entry for the above table for that I am using anyMatch
Assert.assertTrue(
result.stream().anyMatch(
ag -> ( "Marvel".equals(ag.get("Name")) && 10==(int)ag.get("Count"))
));
How can I use multiple Predicates ? I can have a list of 1000 HashMap, I just want to check if any two Hash-map from my list contains those two entries.
Your data structure seems wrong for a start. A List<Map<String, Object>>, where each map represents a row and has only one key and one value? You just need a Map<String, Integer>. The string is the name, the integer is the count. Remember to give it a meaningful name, e.g. comicUniverseToSuperheroFrequency.
With that said, Predicate has an and method which you can use to chain conditions together. It might look something like this:
public static void main(String[] args)
{
Map<String, Integer> comicUniverseToSuperheroFrequency = /*something*/;
boolean isMarvelCountTen = comicUniverseToSuperheroFrequency.entrySet().stream()
.anyMatch(row -> isMarvel().and(isTen()).test(row));
}
private static Predicate<Map.Entry<String, Integer>> isMarvel()
{
return row -> "Marvel".equals(row.getKey());
}
private static Predicate<Map.Entry<String, Integer>> isTen()
{
return row -> row.getValue() == 10;
}

Referencing the values in one array list to values in another

Is there a data structure in Java where the values in one ArrayList can be used to reference the values in another? For example:
DataStructure<ArrayList<String>, ArrayList<String>> ds = new DataStructure<ArrayList<String>, ArrayList<String>>();
The purpose would be that I could iterate through the data structure later and get both values. For example:
for(int i=0; i<ds.size(); i++) {
String val1 = ds.get(i).getIndex1().getArrayListValueAt(i);
String val2 = ds.get(i).getIndex2().getArrayListValueAt(i);
}
I know this looks odd, but it's hard for me to picture.
P.S. Would it be easier to make sure the indexes are the same in both array lists and just loop through one, and as one is grabbed reference the same index in the other. For instance:
int i = 0;
for(String value : values) {
String val1 = value;
String val2 = list2.get(i);
i++;
}
Thanks.
I think for your purpose, the Map structure would be better suited. It's a dictionary, so one value is the key and the other is its mapped value.
Map<String, String> ds = new HashMap<>();
Then to loop and access the values, you can use its keySet() method like so...
for (String k : ds.keySet()) {
String key = k;
String value = ds.get(k);
}
And to add new key/value pairs to the data structure, you use the put(k, v) method.
ds.put("thisIsAKey", "thisIsTheValue");
Not sure if I understand correctly, it sounds like you wanna have a list which each element in the list would hold pair of values. Would below solution help?
// A class which holds two values...
class MyPair {
String val1;
String val2;
}
// And then you list would be ..
List<MyPair> myList = new ArrayList();
// When you looping your list... it would be like something below
for(MyPair mypair : myList) {
String val1 = mypair.val1;
String val2 = mypair.val2;
}
You can use e.g. Map for your problem, because you can storage all needed collection in one place
Map<String, List<String>> map = new HashMap<>();
or e.g.:
Map<List<String>, List<String>> map = new HashMap<>();
And then you can e.g. String as key and e.g. List<T> as value
Very important thing is which object do you use as key, because it must have equals/hashCode (if is your object it must be #Override) and next, great when this object is immutable

What is the best way to iterate two hashmap in same loop in java?

What's the best way to iterate over the below two maps together? I want to compare two maps values which are strings and have to get the keys and values.
HashMap<String, String> map1;
HashMap<String, String> map2;
There really isn't a better option than
for (Map.Entry<String, String> entry1 : map1.entrySet() {
String key = entry1.getKey();
String value1 = entry1.getValue();
String value2 = map2.get(key);
// do whatever with value1 and value2
}
Depending on what exactly you're trying to do, there are several reasonable options:
Just compare the contents of two maps
Guava provides a Maps.difference() utility that gives you a MapDifference instance letting you inspect exactly what is the same or different between two maps.
Iterate over their entries simultaneously
If you just want to iterate over the entries in two maps simultaneously, it's no different than iterating over any other Collection. This question goes into more detail, but a basic solution would look like this:
Preconditions.checkState(map1.size() == map2.size());
Iterator<Entry<String, String>> iter1 = map1.entrySet().iterator();
Iterator<Entry<String, String>> iter2 = map2.entrySet().iterator();
while(iter1.hasNext() || iter2.hasNext()) {
Entry<String, String> e1 = iter1.next();
Entry<String, String> e2 = iter2.next();
...
}
Note there is no guarantee these entries will be in the same order (and therefore e1.getKey().equals(e2.getKey()) may well be false).
Iterate over their keys to pair up their values
If you need the keys to line up, iterate over the union of both maps' keys:
for(String key : Sets.union(map1.keySet(), map2.keySet()) {
// these could be null, if the maps don't share the same keys
String value1 = map1.get(key);
String value2 = map2.get(key);
...
}
My case if maps are the same sizes
IntStream.range(0, map1.size()).forEach(i -> map1.get(i).equals(map2.get(i));
You can do something like:
for (String key : map1.keySet()) {
if (map2.containsKey(key)) {
// do whatever
} else {
// map2 doesn't have entry with map1 key
}
}

Using HashMap for getting repeating occurences

I have a HashMap which is populated with String and Integer:
Map<String, Integer> from_table;
from_table = new HashMap<String, Integer>();
Next i want to get all the keys of items which there value (the Integer) is above x.
For example all the keys which their value is over 4.
Is there a fast method for doing that?
Thnaks!
public static void printMap(Map mp) {
for(Map.Entry pairs : mp.entrySet()) {
if(pairs.getValue() >= 4)
{
System.out.println(pairs.getKey());
}
}
}
Well, iterate over the key-value pairs and collect keys where values meet the criteria
//collect results here
List<String> resultKeys= new ArrayLIst<String>();
//hash map iterator
Iterator<String> it = from_table.keySet();
while(it.hasNext()) {
//get the key
String key= it.next();
/get the value for the key
Integer value= from_map.get(key);
//check the criteria
if (value.intValue() > x) {
resultKeys.add(key);
}
}
Not in standard Java. Guava has method called filter doing exactly this as a one-liner (+ the predicate).
As the above solution states there is nothing faster than just looping through, but an alternative solution would be to edit the function to put something in the map and have it check if there are 4 or more items, if there are it adds it to a new list with only objects with a count of more than 4

Java code to Prevent duplicate <Key,Value> pairs in HashMap/HashTable

I have a HashMap as below (assuming it has 10,0000 elements)
HashMap<String,String> hm = new HashMap<String,String>();
hm.put("John","1");
hm.put("Alex","2");
hm.put("Mike","3");
hm.put("Justin","4");
hm.put("Code","5");
==========================
Expected Output
==========================
Key = John",Value = "1"
Key = Alex",Value = "2"
Key = Mike",Value = "3"
Key = Justin",Value = "4"
Key = Code",Value = "5"
===========================
I need Java code to prevent Addition of Duplicate <Key,Value> Pairs in HashMap such
that below conditions are staisfied.
1> hm.put("John","1"); is not accepted/added again in the Map
2> hm.put("John","2"); is not accepted/added again in the Map
Hope its clear.
Java code provided will be appreciated.(generic solution needed since i can add any duplicate to the existing map)
You can wrap HashMap in a class, which delegates put, get, and other methods you use from HashMap. This method is wasteful but safe, since it doesn't depend on the internal implementation of HashMap, AbstractMap. The code below illustrates put, get delegating:
public class Table {
protected java.util.HashMap<String, Integer> map =
new java.util.HashMap<String, Integer>();
public Integer get(String key) { return map.get(key); }
public Integer put(String key, Integer value) {
if (map.containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return map.put(key, value);
}
}
// other methods goes here
}
Another option is to make a class which extends HashMap, and depend on its internal implementation. Java 1.6 sources shows that put is called only in putAll in HashMap, so you can simply override put method:
public class Table extends java.util.HashMap<String, Integer> {
public Integer put(String key, Integer value) {
if (containsKey(key)) {
// implement the logic you need here.
// You might want to return `value` to indicate
// that no changes applied
return value;
} else {
return super.put(key, value);
}
}
}
Another option is similar to the first, and can make an utility method in your class which contains the HashMap instance and call that method wherever you need put something to your map:
public final Integer putToMap(String key, String value) {
if(this.map.containsKey(key)) {
return value;
} else {
return this.map.put(key, value);
}
}
This is an "inline" equivalent of checking manually.
I note that you clarify the question by suggesting you might have "100000000 elements". You still won't have duplicates in the HashMap, because, as two other posters have pointed out, you can't get duplicate keys in a Map. I'm still not sure we understand the question, though, as it's not at all clear how you expected to generate the block titled "Output", or what you intend to do with it.
This may be old question but I thought to share my experience with this. As others pointed out you can't have the same element in a HashMap. By default HashMap will not allow this but there are some cases that you could end up with two or more elements are almost alike that you do not accept but HashMap will. For example, the following code defines a HashMap that takes an array of integers as a key then add :
HashMap<int[], Integer> map1 = new HashMap<>();
int[] arr = new int[]{1,2,3};
map1.put(arr, 4);
map1.put(arr, 4);
map1.put(arr, 4);
At this point, the HashMap did not allow dublicating the key and map1.size() will return 1. However, if you added elements without creating the array first things will be different:
HashMap<int[], Integer> map2 = new HashMap<>();
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
map2.put(new int[]{4,5,6}, 6);
This way, the HashMap will add all the three new elements so the map2.size() will return 3 and not 1 as expected.
The explanation is that with the first map I created the object arr once and tried to add the same object 3 times which HashMap does not allow by default so only the last usage will be considered. With the second map, however, evey time I recreate a new object on the stack. The three objects created are different and separated thought the three of them have the same data but they are different. That's why HashMap allowed them as different keys.
Bottom line, you don't need to prevent HashMap from adding dublicated keys because it won't by design. However, you have to watch out how you define these keys because the fault may be on your side.
List<String> keys = new ArrayList<String>(); (1000000)
List<String> values = new ArrayList<String>(); (1000000)
Map<String, String> map = new HashMap<String, String>();
int i =0;
for(String key : keys){
String returnedValue = map.put(key, values.get(i));
if(returnedValue!=null){
map.put(key, returnedValue);
system.out.println("Duplicate key trying to be entered with new value so reverting the duplicate key ="+key+"new Value"+values.get(i));
}
}
Unfortunately, it is the way that Map works.
The easiest workaround is to remove all pre existed keys and their values by calling hm.remove() first! like this:
for (String name : names) {
hm.remove(name);
hm.put(name,uri.getQueryParameter(name));
}
And if you don't use a for loop just call it like this:
hm.remove("John");
hm.put("John","1");
hm.remove("Alex");
hm.put("Alex","2");
hm.remove("Mike");
hm.put("Mike","3");
And so on ...
see even if u write same key values multiple times you will just have unique set of pairs. Check that by either iterating or by doing hm.size();
if(hm.put("John","1") != null)
{
// "John" was already a key in the map. The sole value for this key is now "1".
}
List<Object> yourElements = new ... // 10000000
for(Object O : yourElements) {
if(myMap.get(O.key)==null) {
myMap.put(O.key,O);
}
}

Categories