Using HashMap for getting repeating occurences - java

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

Related

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
}
}

Store in a map a key with multiple values

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.

Sorted map not outputting sorted. Do I understand maps.

I have been reading up on maps and understand some of the differences in tree maps and hash, sorted maps. I was trying to get a map to be sorted when outputting it.
What I needed to be able to do was:
Take a text file and read in the content.
Break it into separate words. Use the words as the key and the value as how many times the key occurs in the txt file.
If the word is at the end of a sentence I am to make it a separate key. E.g., my and my. are two separate keys.
My problem is that no matter if I declare it as a tree, hash or sorted map, I can't get it to output/iterate through in an ordered way. I wanted it to output with the highest occurring value first, but I can't even get it to output with the key in any order.
public static Map<String, Integer> createDictionary(String _filename)
{
TreeMap<String, Integer> dictionary = new TreeMap<String, Integer>(); // Changed Hash to _______
try {
FileReader myFileReader=new FileReader(_filename); // File reader stream open
BufferedReader myBuffReader=new BufferedReader(myFileReader);
String str = "\0";
while (str != null) { // While there are still strings in the file
str = myBuffReader.readLine(); // We read a line into the str variable
if (str != null) { // Make sure its not the last line/EOF
// System.out.println(str); // Used for testing.
StringTokenizer myTokenStr=new StringTokenizer(str," \t"); // Create a StringToken obj from the string
while (myTokenStr.hasMoreTokens()) {
String tokStr = myTokenStr.nextToken(); // Each token is put into an individual string
// System.out.println(tokStr);
if (dictionary.containsKey(tokStr)) {
int value = dictionary.get(tokStr); // Add one to the integer value
// dictionary.remove(tokStr); // Was doing this way but just using put method works
// dictionary.put(tokStr, value + 1);
dictionary.put(tokStr, value + 1);
}
else {
dictionary.put(tokStr, 1); // Add the string as the key with an int value of one for the value
}
}
}
}
myBuffReader.close(); // Close stream
myFileReader.close(); // Close stream
}
catch (FileNotFoundException e) {
System.out.println("File Not Found");
}
catch (IOException e) { }
// System.out.println(dictionary.entrySet());
return dictionary;
}
Your map is sorted alphabetically, not by number of occurrences. You need to postprocess the map after the initial parsing. I would suggest:
Parse file into HashMap<String, Integer>
Iterate through HashMap, and add elements to a TreeMap<Integer, Set<String> > (see below).
Output the TreeMap.
You can achieve step 2. by something like:
TreeMap<Integer, Set<String> > treeMap = new TreeMap<Integer, Set<String> > ();
for (Map.Entry<String, Integer> entry: hashMap) {
Set<String> set = treeMap.get(entry.value());
if (set == null) {
set = new TreeSet<String>();
treeMap.put(entry.value(), set);
}
set.add(entry.key());
}
Using TreeSet here sorts the words with same number of occurrences alphabetically, you could use any other Set or List though.
For descending order in step 3.:
for (Map.Entry<Integer, Set<String> > entry: treeMap.descendingMap())
for (String word: entry.getValue())
System.out.println(String.format("%d: %s", entry.getKey(), word));
That should do it.
This is the documentation for TreeMap, lifted from its Javadoc:
public class TreeMap extends AbstractMap
implements NavigableMap, Cloneable, Serializable
A Red-Black tree based NavigableMap implementation. The map is sorted according
to the natural ordering of its keys, or by a Comparator provided at map creation
time, depending on which constructor is used.
In your case, the keys would be strings, and you should expect that iteration will reveal the map to be sorted according to their 'natural order'. Here's an example of the output generated by a TreeMap consisting of String keys and Integer values:
Map<String, Integer> map = new TreeMap<String, Integer>();
map.put("Hello", Integer.valueOf(8));
map.put("Abraham", Integer.valueOf(81));
map.put("Smell", Integer.valueOf(-1));
map.put("Carpet", Integer.valueOf(4));
map.put("Sex", Integer.valueOf(23));
for(String key: map.keySet()) {
System.out.printf("Map entry %s: %d\n", key, map.get(key));
}
Output:
Map entry Abraham: 81
Map entry Carpet: 4
Map entry Hello: 8
Map entry Sex: 23
Map entry Smell: -1
As you can see, iterating over the map's keys produces as ordered result. This order is defined by the natural order of String. Unfortunately, you cannot implement a SortedMap that sorts on values, which is what I believe you want to do. You can however, sort the entries in the Map outside of it. See more details in this other SO post: TreeMap sort by value.
Map is a kind of messy abstraction for this sort of thing, but I'm going to throw out Guava's Multiset as a way to address this use case, as it's expressly designed for "counting occurrences of things."
In particular,
return Multisets.copyHighestCountFirst(HashMultiset.copyOf(listOfWords));
returns a Multiset that iterates over elements in order of descending frequency in listOfWords.
There are many questions on SO, by the way, relating to ordering maps by values instead of keys, but I prefer this solution.

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);
}
}

Iterating over and deleting from Hashtable in Java

I have a Hashtable in Java and want to iterate over all the values in the table and delete a particular key-value pair while iterating.
How may this be done?
You need to use an explicit java.util.Iterator to iterate over the Map's entry set rather than being able to use the enhanced For-loop syntax available in Java 6. The following example iterates over a Map of Integer, String pairs, removing any entry whose Integer key is null or equals 0.
Map<Integer, String> map = ...
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, String> entry = it.next();
// Remove entry if key is null or equals 0.
if (entry.getKey() == null || entry.getKey() == 0) {
it.remove();
}
}
You can use Enumeration:
Hashtable<Integer, String> table = ...
Enumeration<Integer> enumKey = table.keys();
while(enumKey.hasMoreElements()) {
Integer key = enumKey.nextElement();
String val = table.get(key);
if(key==0 && val.equals("0"))
table.remove(key);
}
You can use a temporary deletion list:
List<String> keyList = new ArrayList<String>;
for(Map.Entry<String,String> entry : hashTable){
if(entry.getValue().equals("delete")) // replace with your own check
keyList.add(entry.getKey());
}
for(String key : keyList){
hashTable.remove(key);
}
You can find more information about Hashtable methods in the Java API
So you know the key, value pair that you want to delete in advance? It's just much clearer to do this, then:
table.delete(key);
for (K key: table.keySet()) {
// do whatever you need to do with the rest of the keys
}

Categories