Merging Treemaps in a list - java

I have a List<Map<String, Object>> which contains the following maps.
Map:{clusterList=[71051], senseId=65786, totalCluster=1}
Map:{clusterList=[71051], senseId=65787, totalCluster=1}
Map:{clusterList=[4985, 71052], senseId=65788, totalCluster=2}
Map:{clusterList=[125840,153610,167812, 65787, 204091, 32586, 65786], senseId=71051, totalCluster=7}
Map:{clusterList=[11470, 65788], senseId=71052, totalCluster=2}
I have traversed the map and checked if senseId is present in the clusterList. But traversing each clusterList with senseId is taking long time with traditional for loop and also I am unable to get the merged list as the following
Map:{clusterList=[125840,153610,167812, 65787, 204091, 32586, 65786], senseId=71051, totalCluster=7}
Map:{clusterList=[4985,11470, 65788], senseId=71052, totalCluster=2}
I cant even remove the map with sensId present in the clusterList as it throws as concurrent operation exception.
Any ideas how to get to the result other than for loop as this list is very small so for loop still works. But I have list with 180 map entries and its hard to traverse the whole list and merge the maps.
I am stuck because the senseId of one map is present in clusterList of other map. So not able to merge them with simple search.

I'm rather sure that the problem is still underspecified. For example, it is not clear how to decide about the final senseId. When you have two maps
Map:{clusterList=[123,456,789], senseId=123, totalCluster=1}
Map:{clusterList=[123,456,666], senseId=456, totalCluster=1}
then (if I understood you correctly) they should be merged. But it is not clear whether the result should be a map
Map:{clusterList=[123,456,789,666], senseId=123, totalCluster=1}
or a map
Map:{clusterList=[123,456,789,666], senseId=456, totalCluster=1}
Apart from that, it seems like the "totalCluster" is the size of the cluster list. This means that it is most likely unnecessary, and if it is not unnecessary, you'd have to specify how it should be treated when two maps are merged.
However, here is a basic approach: One can create a map from senseId to maps with this senseId, and afterwards collect the maps that contain a certain senseId in their cluster list in order to find out which maps have to be merged.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapMergeTest
{
public static void main(String[] args)
{
List<Map<String, Object>> maps = createInput();
System.out.println("Input:");
for (Map<String, Object> map : maps)
{
System.out.println(map);
}
List<Map<String, Object>> result = createMergedMapsList(maps);
System.out.println("Result:");
for (Map<String, Object> map : result)
{
System.out.println(map);
}
}
private static List<Map<String, Object>> createInput()
{
List<Map<String, Object>> maps = new ArrayList<Map<String, Object>>();
// senseId clusterList...
maps.add(createMap(65786, 71051));
maps.add(createMap(65787, 71051));
maps.add(createMap(65788, 4985, 71052));
maps.add(createMap(71051, 125840, 153610, 167812,
65787, 204091, 32586, 65786));
maps.add(createMap(71052, 11470, 65788));
return maps;
}
private static Map<String, Object> createMap(
Integer senseId, Integer ... clusters)
{
Map<String, Object> result = new LinkedHashMap<String, Object>();
result.put("senseId", senseId);
result.put("clusterList", new ArrayList<Integer>(Arrays.asList(clusters)));
return result;
}
private static List<Map<String, Object>> createMergedMapsList(
List<Map<String, Object>> maps)
{
Map<Integer, Map<String, Object>> senseIdToMap =
createSenseIdToMap(maps);
Map<Integer, Map<String, Object>> copy =
new LinkedHashMap<Integer, Map<String,Object>>(senseIdToMap);
for (Entry<Integer, Map<String, Object>> e : copy.entrySet())
{
Integer senseId = e.getKey();
Map<String, Object> map = e.getValue();
List<Integer> clusterList = getClusterList(map);
List<Map<String, Object>> mapsToMerge =
new ArrayList<Map<String,Object>>();
mapsToMerge.add(map);
for (Integer cluster : clusterList)
{
Map<String, Object> mapToMerge =
senseIdToMap.get(cluster);
if (mapToMerge != null)
{
mapsToMerge.add(mapToMerge);
senseIdToMap.remove(cluster);
}
}
if (mapsToMerge.size() > 1)
{
Map<String, Object> mergedMap = mergeMaps(mapsToMerge);
List<Integer> mergedClusterList = getClusterList(mergedMap);
mergedClusterList.remove(senseId);
senseIdToMap.put(senseId, mergedMap);
}
}
return new ArrayList<Map<String,Object>>(senseIdToMap.values());
}
private static Map<Integer, Map<String, Object>> createSenseIdToMap(
List<Map<String, Object>> maps)
{
Map<Integer, Map<String, Object>> senseIdToMap =
new LinkedHashMap<Integer, Map<String,Object>>();
for (Map<String, Object> map : maps)
{
Integer senseId = (Integer)map.get("senseId");
senseIdToMap.put(senseId, map);
}
return senseIdToMap;
}
private static Map<String, Object> mergeMaps(List<Map<String, Object>> list)
{
Map<String, Object> mergedMap = new LinkedHashMap<String, Object>();
Map<String, Object> firstMap = list.get(0);
mergedMap.put("senseId", firstMap.get("senseId"));
Set<Integer> mergedClusterList = new LinkedHashSet<Integer>();
for (Map<String, Object> map : list)
{
List<Integer> clusterList = getClusterList(map);
mergedClusterList.addAll(clusterList);
}
mergedMap.put("clusterList", new ArrayList<Integer>(mergedClusterList));
return mergedMap;
}
private static List<Integer> getClusterList(Map<String, Object> map)
{
Object object = map.get("clusterList");
return (List<Integer>)object;
}
}

Related

How do you map unique values from a list of maps to a new list of maps in Java? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
I have a list of maps
List<Map<String, Object>> myList = [{value1=3, value2=11},{value1=8, value2=16},{value1=3, value2=11},{value1=10, value2=11} ...]
and I want to extract value2 to a new list of maps but have only unique values there:
List<Map<String, Object>> res = [{value2=11},{value2=16} ...]
What id the best way to do it?
Try this. Here first I am creating a list of Entry<value2, anyUniqueValue> by using 2 functions.
First filtering only those Entries which has key value2 by using function filterFunction
Secondly by filtering unique value by using function distinctByValue
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
public class Demo{
public static void main(String[] args) {
List<Map<String, Object>> myList = new ArrayList<>();
Map<String, Object> map1 = new HashMap<>();
map1.put("value1", 3);
map1.put("value2", 11);
Map<String, Object> map2 = new HashMap<>();
map2.put("value1", 8);
map2.put("value2", 16);
Map<String, Object> map3 = new HashMap<>();
map3.put("value1", 3);
map3.put("value2", 11);
Map<String, Object> map4 = new HashMap<>();
map4.put("value1", 10);
map4.put("value2", 11);
myList.add(map1);
myList.add(map2);
myList.add(map3);
myList.add(map4);
List<Entry<String, Object>> list = myList.stream().flatMap(map -> map.entrySet().stream())
.filter(s -> filterFuction(s)).filter(distinctByValue(entry -> entry.getValue()))
.collect(Collectors.toList());
List<Map<String, Object>> list1 = list.stream().map(t -> {
Map<String, Object> map = new HashMap<>();
map.put(t.getKey(), t.getValue());
return map;
}).collect(Collectors.toList());
System.out.println(list1);
}
public static <T> Predicate<T> distinctByValue(Function<? super T, ?> keyExtractor) {
Map<Object, Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
public static boolean filterFuction(Entry<String, Object> entry) {
if (entry.getKey().equals("value2"))
return true;
return false;
}
}

Join List of Map Objects in java

Have a two list of Map, should do the dataset joins on those two lists, leftJoin, rightJoin, outerJoin and innerJoin
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
public class JoinMap {
public static List<Map<String, Object>> getFirstMap() {
List<Map<String, Object>> data = new ArrayList<>();
Map<String, Object> dataMap2 = new HashMap<>();
dataMap2.put("user", "vs");
dataMap2.put("data1", 12.0);
dataMap2.put("data2", 42.0);
dataMap2.put("data3", 32.0);
data.add(dataMap2);
Map<String, Object> dataMap1 = new HashMap<>();
dataMap1.put("user", "samraj");
dataMap1.put("data1", 11.0);
dataMap1.put("data2", 41.0);
dataMap1.put("data3", 31.0);
data.add(dataMap1);
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("user", "varghees");
dataMap.put("data1", 10.0);
dataMap.put("data2", 40.0);
dataMap.put("data3", 30.0);
data.add(dataMap);
return data;
}
public static List<Map<String, Object>> getSecondMap() {
List<Map<String, Object>> data = new ArrayList<>();
Map<String, Object> dataMap2 = new HashMap<>();
dataMap2.put("user", "vs");
dataMap2.put("test1", 12.0);
dataMap2.put("test2", 42.0);
dataMap2.put("test3", 32.0);
data.add(dataMap2);
Map<String, Object> dataMap1 = new HashMap<>();
dataMap1.put("user", "samraj");
dataMap1.put("test1", 11.0);
dataMap1.put("test2", 41.0);
dataMap1.put("test3", 31.0);
data.add(dataMap1);
Map<String, Object> dataMap = new HashMap<>();
dataMap.put("user", "varghees");
dataMap.put("test1", 10.0);
dataMap.put("test2", 40.0);
dataMap.put("test3", 30.0);
data.add(dataMap);
return data;
}
public static List<Map<String, Object>> leftJoin(List<Map<String, Object>> map1, List<Map<String, Object>> map2) {
}
public static List<Map<String, Object>> rightJoin(List<Map<String, Object>> map1, List<Map<String, Object>> map2) {
}
public static List<Map<String, Object>> innerJoin(List<Map<String, Object>> map1, List<Map<String, Object>> map2) {
}
public static List<Map<String, Object>> outerJoin(List<Map<String, Object>> map1, List<Map<String, Object>> map2) {
}
public static void main(String[] argv) {
List<Map<String, Object>> firstMap = getFirstMap();
List<Map<String, Object>> secondMap = getSecondMap();
}
}
Is there any easy functions available in Java8 to accomplish these methods? I am trying to avoid iterating over data and populate new dataset.
Sure there is. Here’s an example using streams for the inner join. I am assuming we know for a fact that we should join on "user" (if not, it’s getting more complicated, but it still can be done).
public static List<Map<String, Object>> innerJoin(List<Map<String, Object>> map1, List<Map<String, Object>> map2) {
return map1.stream().flatMap(m1 ->
map2.stream()
.filter(m2 -> m1.get("user").equals(m2.get("user")))
.map((Map<String, Object> m2) -> {
Map<String, Object> mr = new HashMap<>();
mr.putAll(m1);
mr.putAll(m2);
return mr;
})
).collect(Collectors.toList());
}
I hope and think you will be able to take the inspiration and do the others yourself.

How do i acess a nested hash map value that i have return from another class ? Java

I am new to hash mapping and I was trying to created a nested hash map on one side of the class and create another class to call it out, so here's how my code looks like
public class Hash {
private HashMap<String, HashMap<String, String>> wow = new HashMap<String, HashMap<String, String>>();
public void SetHash(){
wow.put("key", new HashMap<String, Object>());
wow.get("key").put("key2", "val2");
}
public HashMap GetMap(){
return wow;
}
}
And on the other class which is the main class it will be like this:
public static void main(String[] args) {
Hash h = new Hash();
h.SetHash();
System.out.println(h.GetMap.get("key").get("key2"));
}
But when I place the second get, there's an error, so I am not sure if this is possible or if I should actually place the hash directly at the main class.
GetMap is a method, not an attribute, so you have to refer it with parenthesis ():
h.GetMap().get("key")
Now, second error. Your Map<String, Map<String, String> named wow contains a values that are objects of the type Map<String, String> so, before the get, you need get the map:
Map<String, String> m = (HashMap<String, String>) h.GetMap().get("key");
And then you can print it:
System.out.println(m.get("key2"));
if you want an ONELINER (is not really clear, but check explanation in comments):
System.out.println(((HashMap<String, String>) h.GetMap().get("key")).get("key2"));
// ↑ casting parenthesis ↑ (
// ↑ this say group IS a map and allow get() ↑
// ↑ system.out.println parenthesis ↑
NOTE: change also this declaration
wow.put("key", new HashMap<String, Object>());
By
wow.put("key", new HashMap<String, String>());
FINAL CODE:
public class Q37066776 {
public static void main(String[] args) {
Hash h = new Hash();
h.SetHash();
Map<String, String> m = (HashMap<String, String>) h.GetMap().get("key");
System.out.println(m.get("key2"));
}
}
class Hash {
private HashMap<String, HashMap<String, String>> wow = new HashMap<String, HashMap<String, String>>();
public void SetHash() {
wow.put("key", new HashMap<String, String>());
wow.get("key").put("key2", "val2");
}
public HashMap GetMap() {
return wow;
}
}
WORKING ONLINE DEMO
but you can always
Do it better! :=)
As pointed by Andrew
you can change return of the method,
But also many other things like:
using less concrete objects (Map instead of HashMap)
follow conventions (GetMap() would be getMap())
Make Hash a static class with static block
If I had to rewrite your code, my result would be like this:
public class Q37066776 {
public static void main(String[] args) {
System.out.println(Hash.getMap().get("key").get("key2"));
}
}
class Hash {
private static Map<String, Map<String, String>> wow = new HashMap<String, Map<String, String>>();
static {
wow.put("key", new HashMap<String, String>());
wow.get("key").put("key2", "val2");
}
public static Map<String, Map<String, String>> getMap() {
return wow;
}
}
You have 3 errors:
GetMap is a method - you need to write GetMap().
you declared the inner Map as HashMap<String, String> - you cannot initialize the inner map to: wow.put("key", new HashMap<String, Object>());
Change it to wow.put("key", new HashMap<String, String>());
In order to access the inner map from the main - you must declare the returned value of GetMap to be Map<String, HashMap<String, String>> instead of just raw type. Otherwise, the outer class won't know that the outer map value is also a hash map.
Instead of using nested maps, you should use google's Guava Table:
http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/collect/Table.html

Itetrate Map<String, Map<String, String>> using java

I have a hashmap used to store the platform details
I need to iterate Map<String, Map<String, String>> finalmapWin8
and get the values and keys of mapWin8
values 33,8 and key BrowserType.CHROME, BrowserType.FIREFOX and BrowserType.IE
Also i want to get the key of 'finalmapWin8' "WIN8_1"
How can i iterate Map<String, Map<String, String>> finalmapWin8
static Map<String, Map<String, String>> finalmapWin8 = new HashMap<Platform, Map<String, String>>();
public static final Map<String, String> mapWin8 = new HashMap<String, String>();
static {
mapWin8.put(BrowserType.CHROME, "33");
mapWin8.put(BrowserType.FIREFOX, "33");
mapWin8.put(BrowserType.IE, "8");
}
static {
finalmapWin8.put("WIN8_1", mapWin8);
}
iteration for Map is the same. since your value for your map is also a Map then you just need another iteration to iterate through it.
for(String s: finalmapWin8.keySet()){
System.out.println(s + " : ");
for(Entry<String, String> entry : finalmapWin8.get(s).entrySet()){
System.out.println(entry);
}
}
You can use a for loop for loop for Map of type Map.Entry<String, Map<String, String>> ... well, that's it.. See the code snippet below -
import java.util.HashMap;
import java.util.Map;
public class Test {
static Map<String, Map<String, String>> finalmapWin8 = new HashMap<String, Map<String,String>>();
public static final Map<String, String> mapWin8 = new HashMap<String, String>();
static {
mapWin8.put("CHROME", "33");
mapWin8.put("FIREFOX", "33");
mapWin8.put("IE", "8");
}
static {
finalmapWin8.put("WIN8_1", mapWin8);
}
public static void main(String[] args) {
for(Map.Entry<String, Map<String, String>> entry : finalmapWin8.entrySet()) {
System.out.println(entry.getValue());
}
}
}
// get the keysets or outer map and then again run a secound loop for inner map.
for (Map.Entry<String, Map<String, String>> entry : firstMap) {
system.out.println("entry="+entry );
}
Refer to How to efficiently iterate over each Entry in a Map?
You can use below code for iterating through HashMap
for (Map.Entry<String, Map<String, String>> entry : finalmapWin8.entrySet()) {
System.out.println("Key:"+entry.getKey());
for (Map.Entry<String, String> entry1 : mapWin8.entrySet()) {
System.out.println("Keys in Second:"+ entry1.getKey()+" Values:"+ entry1.getValue());
}
}

Why does this Hashmap Iteration not work? I get a NullPointer Exception

Map<String, String> listOfIndexes = INDEXED_TABLES.get(tableName);
Iterator it = listOfIndexes.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pairs = (Map.Entry)it.next();
System.out.println(pairs.getKey());
}
My Hashmap is like this :
public static Map<String, Map<String, String>> INDEXED_TABLES = new HashMap<String, Map<String, String>>()
{{
put("employee", EMPLOYEE);
}};
public static Map<String, String> EMPLOYEE = new HashMap<String, String>()
{{
put("name", "Test");
put("age", "Test");
put("sex", "test");
}};
This is because you outsmarted yourself: your initializers depend on the order of execution. At the time this line runs
put("employee", EMPLOYEE);
EMPLOYEE is still null, so that's what gets put into your Map<String,Map<String,String>>.
You can switch the order of initializers to fix this problem. However, you would be better if you put initialization code into a separate initializer, rather than using anonymous classes with custom initializers:
public static Map<String, Map<String, String>> INDEXED_TABLES = new HashMap<String, Map<String, String>>();
public static Map<String, String> EMPLOYEE = new HashMap<String, String>();
static {
EMPLOYEE.put("name", "Test");
EMPLOYEE.put("age", "Test");
EMPLOYEE.put("sex", "test");
INDEXED_TABLES.put("employee", EMPLOYEE);
}
It looks like you are putting EMPLOYEE into the map before it has been initialized, so it will be null (and remain so, even if you assign something to EMPLOYEE later).
Reverse the order of the two statements.
Or, while in general I disapprove of the double-brace-initializer (hopefully, we'll get proper Collection literals in Java 8):
public static Map<String, Map<String, String>> INDEXED_TABLES =
new HashMap<String, Map<String, String>>(){{
put("employee", new HashMap<String, String>(){{
put("name", "Test");
put("age", "Test");
put("sex", "test");
}}
}}

Categories