iteration over hashmap list - java

I want to iterate over the HashMap list and retrieve the key and the values (value 1 and value2). There is a error at this line that says
"Type mismatch: cannot convert from element type Object to Map.Entry>"
for (Map.Entry<String, List<String>> entry : Map.entrySet())
Am I doing anything wrong. Please help me out. Here is the entire code.
public static void main(String[] args) {
Map<String, List<String>> conceptMap = new HashMap<String, List<String>>();
Map<String, List<String>> PropertyMap = new HashMap<String, List<String>>();
try{
Scanner scanner = new Scanner(new FileReader("C:/"));
while (scanner.hasNextLine()){
String nextLine = scanner.nextLine();
String [] column = nextLine.split(":");
if (column[0].equals ("Property")){
if (column.length == 4) {
PropertyMap.put(column [1], Arrays.asList(column[2], column[3]));
}
else {
conceptMap.put (column [1], Arrays.asList (column[2], column[3]));
}
}
for (Map.Entry<String, List<String>> entry : Map.entrySet()) {
String key = entry.getKey();
List<String> valueList = entry.getValue();
System.out.println("Key: " + key);
System.out.print("Values: ");
for (String s : valueList) {
System.out.print(s + " ");
}
}
}
scanner.close();
}
catch (Exception e) {
e.printStackTrace();
}

Change Map.entrySet() to PropertyMap.entrySet() or conceptMap.entrySet()

The Map.entrySet() method declared by the Map interface returns a collection-view of the map (returns a Set). Each of these set elements is a Map.Entry object. The only way to obtain a reference to a map entry is from the iterator of this collection-view.
If you want to return a Set you inserted into the map, you have to call it on the Collection you placed it in:
PropertyMap.entrySet() and conceptMap.entrySet() will return Sets.
Map.entrySet() is not calling the method on either of your instantiated Maps.

Map.entrySet() returns a collection view of the map.change it in to conceptMap.entrySet() or
propertyMap.entrySet

Related

Reversing key value pairs in a HashMap

I have a data structure as follows:
Map<String,ArrayList<String>> graph = new HashMap<String,ArrayList<String>>();
This is essentially a hash map which puts string values as keys and stores array list of strings in the value for the keys.
Now I am trying to reverse the key value pattern to make value the key and key the value. The way I am doing it is as follows:
private Map<String,ArrayList<String>> reverseAdjList(Map<String,ArrayList<String>> adjList){
Map<String,ArrayList<String>> tGraph = new HashMap<String,ArrayList<String>>();
for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
ArrayList<String> values = new ArrayList<>();
values.add(key);
ArrayList<String> value = entry.getValue();
for(String v:value){
if(tGraph.containsKey(v)){
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
return tGraph;
}
So this works for me in reversing the hash map keys values pattern for small data set however when I try it on a larger dataset I run into
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.addAll(ArrayList.java:579)
at GraphProcessor.reverseAdjList(GraphProcessor.java:67)
at GraphProcessor.SCC(GraphProcessor.java:135)
at GraphProcessor.<init>(GraphProcessor.java:50)
at GraphProcessor.main(GraphProcessor.java:250)
I know this is a very naïve and wrong approach to do it, what is a better and correct way to do it?
There's a bug in your code:
for (Map.Entry<String, ArrayList<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
ArrayList<String> values = new ArrayList<>(); // Wrong place for this variable.
values.add(key);
ArrayList<String> value = entry.getValue();
for(String v:value){
if(tGraph.containsKey(v)){
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
The local variable values should be in the nested for loop, otherwise values are accumulated for all later new key v and will cost a lot of memory if your dataset is large, it should be:
private Map<String, ArrayList<String>> reverseAdjList(Map<String, List<String>> adjList) {
Map<String, ArrayList<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
String key = entry.getKey();
List<String> value = entry.getValue();
for (String v : value) {
ArrayList<String> values = new ArrayList<>();
values.add(key);
if (tGraph.containsKey(v)) {
values.addAll(tGraph.get(v));
}
tGraph.put(v, values);
}
}
return tGraph;
}
But actually you don't need to create a new List instance for each inner for step, try the following code with JDK 1.8:
private Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
Map<String, List<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
for (String value : entry.getValue()) {
tGraph.computeIfAbsent(value, v -> new ArrayList<>()).add(entry.getKey()); // Updated according comment from #shmosel
}
}
return tGraph;
}
If you're using older version of jdk, you can try:
private Map<String, List<String>> reverseMap(Map<String, List<String>> adjList) {
Map<String, List<String>> tGraph = new HashMap<>();
for (Map.Entry<String, List<String>> entry : adjList.entrySet()) {
for (String value : entry.getValue()) {
List<String> newValues = tGraph.get(value);
if (newValues == null) {
newValues = new ArrayList<>();
tGraph.put(value, newValues);
}
newValues.add(entry.getKey());
}
}
return tGraph;
}
Hope this could be helpful :-)

Iterate over List<Map<String, String>> in Java

I'm trying to iterate List<Map<String, String>> in Java. However, I'm not able to iterate it properly. Can any one guide me?
Iterator it = list.iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry) it.next();
System.out.println(pairs.getKey() + " = " + pairs.getValue());
}
Thanks,
public static void main(String[] args) {
List<Map<String, String>> myListOfMaps = new ArrayList<Map<String, String>>();
Map<String, String> map1 = new HashMap<String, String>();
map1.put("Fname", "Ankur");
Map<String, String> map2 = new HashMap<String, String>();
map2.put("Lname", "Singhal");
myListOfMaps.add(map1);
myListOfMaps.add(map2);
for (int i = 0 ; i < myListOfMaps.size() ; i++) {
Map<String, String> myMap = myListOfMaps.get(i);
System.out.println("Data For Map" + i);
for (Entry<String, String> entrySet : myMap.entrySet()) {
System.out.println("Key = " + entrySet.getKey() + " , Value = " + entrySet.getValue());
}
}
}
output
Data For Map0
Key = Fname , Value = Ankur
Data For Map1
Key = Lname , Value = Singhal
Forget using the iterator directly, why not simply this:
List<Map<String,String>> l = new ArrayList<>();
...
// add map elements to list
...
for (Map<String,String> m:l) {
for (Map.Entry<String,String> e:m.entrySet()) {
String key = e.getKey();
String value = e.getValue();
// Do something with key/value
}
}
This is called an Enhanced for Loop. Internally it will handle it as a for loop traversing the iterator of any collection, or any other implementation of the Iterable Interface.
It was already used for traversing the Map Entries in one answer, so why not for the list of maps?
Of course, for nested collections, you also need to know how to nest your for-loops (how you put one for loop inside the other).
You iterate over a list with elements of type Map<String, String>. So casting to Map.Entry will give you a ClassCastException.
Try it like this
Iterator it = list.iterator();
while (it.hasNext()) {
Map<String, String> map = (Map<String, String>) it.next();
for (Map.Entry entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
It would be easier for you, if you didn't use the raw types Iterator and Map.Entry. Use generics wherever possible. So the code would look like this:
Iterator<Map<String, String>> it = list.iterator();
while (it.hasNext()) {
Map<String, String> map = it.next(); //so here you don't need a potentially unsafe cast
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " = " + entry.getValue());
}
}
list has no entySet() method!
Try this:
final Iterator<Map<String, String>> it = list.iterator();
while (it.hasNext())
{
Map<String, String> mapElement = it.next();
// do what you want with the mapElement
}
Of course, you will need another loop to iterate over the elements in the map.

how to merge more than one hashmaps also sum the values of same key in java

ı am trying to merge more than one hashmaps also sum the values of same key,
ı want to explain my problem with toy example as follows
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
ı tried putall
m.putAll(m2);
output is as follows
{banana=6, apple=9, pear=3}
but its result is not true for this problem.
ı want to output as
{banana=6, apple=11, pear=3}
how can ı get this result in java?
If you are using Java 8, you can use the new merge method of Map.
m2.forEach((k, v) -> m.merge(k, v, (v1, v2) -> v1 + v2));
This is a very nice use case for Java 8 streams. You can concatentate the streams of entries and then collect them in a new map:
Map<String, Integer> combinedMap = Stream.concat(m1.entrySet().stream(), m2.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
There are lots of nice things about this solution, including being able to make it parallel, expanding to as many maps as you want and being able to trivial filter the maps if required. It also does not require the orginal maps to be mutable.
This method should do it (in Java 5+)
public static <K> Map<K, Integer> mergeAndAdd(Map<K, Integer>... maps) {
Map<K, Integer> result = new HashMap<>();
for (Map<K, Integer> map : maps) {
for (Map.Entry<K, Integer> entry : map.entrySet()) {
K key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
Here's my quick and dirty implementation:
import java.util.HashMap;
import java.util.Map;
public class MapMerger {
public static void main(String[] args) {
HashMap<String, Integer> m = new HashMap<>();
HashMap<String, Integer> m2 = new HashMap<>();
m.put("apple", 2);
m.put("pear", 3);
m2.put("apple", 9);
m2.put("banana", 6);
final Map<String, Integer> result = (new MapMerger()).mergeSumOfMaps(m, m2);
System.out.println(result);
}
public Map<String, Integer> mergeSumOfMaps(Map<String, Integer>... maps) {
final Map<String, Integer> resultMap = new HashMap<>();
for (final Map<String, Integer> map : maps) {
for (final String key : map.keySet()) {
final int value;
if (resultMap.containsKey(key)) {
final int existingValue = resultMap.get(key);
value = map.get(key) + existingValue;
}
else {
value = map.get(key);
}
resultMap.put(key, value);
}
}
return resultMap;
}
}
Output:
{banana=6, apple=11, pear=3}
There are some things you should do (like null checking), and I'm not sure if it's the fastest. Also, this is specific to integers. I attempted to make one using generics of the Number class, but you'd need this method for each type (byte, int, short, longer, etc)
ı improve Lucas Ross's code. in stead of enter map by one by in function ı give all maps one times to function with arraylist of hashmap like that
public HashMap<String, Integer> mergeAndAdd(ArrayList<HashMap<String, Integer>> maplist) {
HashMap<String, Integer> result = new HashMap<>();
for (HashMap<String, Integer> map : maplist) {
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String key = entry.getKey();
Integer current = result.get(key);
result.put(key, current == null ? entry.getValue() : entry.getValue() + current);
}
}
return result;
}
}
it works too. thanks to everbody
Assume that you have many HashMaps: Map<String,Integer> map1, map2, map3;
Then you can use Java 8 streams:
Map<String,Integer> combinedMap = Stream.of(map1, map2, map3)
.flatMap(map -> map.entrySet().stream())
.collect(Collectors.groupingBy(Map.Entry::getKey,
Collectors.summingInt(Map.Entry::getValue)));
If the key exists, add to it's value. If not insert.
Here is a simple example which merges one map into another:
Foo oldVal = map.get(key);
if oldVal == null
{
map2.put(key, newVal);
}
else
{
map2.put(key, newVal + oldVal);
}
Obviously you have to loop over the first map so you can process all of it's entries but that's trivial.
Something like this should work:
for (Map.Entry<String, Integer> entry : map.entrySet()) {
String map1_key = entry.getKey();
int map1_value = entry.getValue();
//check:
if(map2.get(map1_key)!=null){
int map2_value = map2.get(map1_key);
//merge:
map3.put(map1_key,map1_value+map2_value);
}else{
map3.put(map1_key,map1_value);
}
}
for (Map.Entry<String, Integer> entry2 : map2.entrySet()) {
String map2_key = entry2.getKey();
int map2_value = entry2.getValue();
//check:
if(map1.get(map2_key)!=null){
int map1_value = map1.get(map2_key);
//merge:
map3.put(map2_key,map1_value+map2_value);
}else{
map3.put(map2_key,map2_value);
}
}

Hashtable Key and value storing in separate array list

java code
Hashtable<String, Integer> gettingStatus = searchActiveAssetStatus();
ArrayList<String> statusValue = new ArrayList<String>();
ArrayList<String> statusCount = new ArrayList<String>();
Set<String> keys = gettingStatus.keySet();
for (String key : keys) {
if (key.contains("Active")) {
statusValue.add(key);
}
if (key.contains("Abandoned")) {
statusValue.add(key);
}
if (key.contains("Deleted")) {
statusValue.add(key);
}
}
for the above i have stored Key in an separate array list (available), at the same time if that key exist in hashtable i want to store the value for that corresponding key in another array list (statusCount) how?
You may use the entrySet() method instead of the keySet() method:
Set<Entry<String, Integer>> entries = gettingStatus.entrySet();
for (Entry<String, Integer> entry : entries) {
String key = entry.getKey();
Integer value = entry.getValue();
if (key.contains("Active")) {
statusValue.add(key);
// Store value
}
if (key.contains("Abandoned")) {
statusValue.add(key);
// Store value
}
if (key.contains("Deleted")) {
statusValue.add(key);
// Store value
}
}
If I got your question right you just have to ask for the value of the corresponding key and put it in the list:
Hashtable<String, Integer> gettingStatus = searchActiveAssetStatus();
ArrayList<String> statusValue = new ArrayList<String>();
ArrayList<String> statusCount = new ArrayList<String>();
Set<String> keys = gettingStatus.keySet();
for (String key : keys) {
if (key.contains("Active") || key.contains("Abandoned") || key.contains("Deleted")) {
statusValue.add(key);
statusCount.add(gettingStatus.get(key).toString());
}
}
Or as Benjamin said just take entrySet() which makes it even easier.

Inverted HashMap in Java whit frequency

I have a HashMap<String, LinkedList<Integer>> and I want to create a hashMapInverted<LinkedList<Integer>, Set<String>> which contains in keys the lists, values of first map, and the values the set of strings which have the same list in first map.
How can I do this?
You can do:
Map<LinkedList<Integer>, Set<String>> mapInverted = new HashMap<>(myMap.size());
for(Entry<<String, LinkedList<Integer>> entry : myMap.entrySet()) {
String key = entry.getKey();
LinkedList<Integer> list = entry.getValue();
Set<String> strings = mapInverted.get(list);
if(strings == null) { // the list has not already been put in the map
strings = new HashSet<String>(); // create a new set
mapInverted.put(list, strings); // put the list and the new set
}
strings.add(key);
}
You can try -
Map<String, LinkedList<Integer>> map =new HashMap<String, LinkedList<Integer>>();
Map<LinkedList<Integer>, Set<String>> invertMap = new HashMap<LinkedList<Integer>, Set<String>>();
for (Entry<String, LinkedList<Integer>> entry : map.entrySet()) {
if(invertMap.containsKey(entry.getValue())){
invertMap.get(entry.getValue()).add(entry.getKey());
}else{
Set<String> set = new HashSet<String>();
set.add(entry.getKey());
invertMap.put(entry.getValue(), set);
}
}

Categories

Resources