Rearrange a map in random fashion - java

I've a SortedMap<String, String> containing key:ID & value:Name.
Now I want to rearrange the elements of this Map in random fashion & store them in separate map.
// Get a random entry from the SortedMap.
String[] keyArr = student.keySet().toArray();
String key = keyArr[new Random().nextInt(keyArr.length)];
// Use a separate List<String> to store which key has been selected, so that they are not re-selected
But above method does not sound very efficient.
Please suggest.
Thank You

You would need to copy the entrySet into a List and shuffle it. This would give you the elements in a random order.
Now you can push those elements to a new LinkedHashMap - to preserve the random order. Something like the following:
final Map<String, Object> m = new TreeMap<>();
m.put("A", 1);
m.put("B", 1);
m.put("C", 1);
m.put("D", 1);
m.put("E", 1);
m.put("F", 1);
m.put("G", 1);
final List<Map.Entry<String, Object>> e = new ArrayList<>(m.entrySet());
Collections.shuffle(e);
final Map<String, Object> r = new LinkedHashMap<>();
for (Map.Entry<String, Object> entry : e) {
r.put(entry.getKey(), entry.getValue());
}

I'm not sure that I got your question, but you should be able to do something like
Map<String, String> result = new LinkedHashMap<>();
List keys = new ArrayList(map.keySet());
Collections.shuffle(keys);
for (Object o : keys) {
// Access keys/values in a random order
result.put(o, map.get(o));
}

Related

Split a map into submaps Java

I have a map with 10 000 keys and it looks like this:
Map<String, List<Integer>>. I want to make a list of Map<String, List<Integer>> which will contains 50 submaps X 200 elements.
This is the code:
Map<String, List<Integer>> map = new HashMap<>();
for (int i = 0; i < 10000; i++) {
map.put(String.valueOf(i),new ArrayList<>(Arrays.asList(new Random().nextInt(100),new Random().nextInt(200),new Random().nextInt(300)
,new Random().nextInt(400))));
}
List<Map<String, List<Integer>>> list = new ArrayList<>();
Map<String,List<Integer>> submap = new TreeMap<>();
List<Map<String, List<Integer>>> sublist = new ArrayList<>();
for (Map.Entry<String, List<Integer>> stringListEntry : map.entrySet()) {
submap.put(stringListEntry.getKey(),stringListEntry.getValue());
if (submap.size() == 200){
sublist.add(submap);
list.addAll(sublist);
sublist.clear();
submap.clear();
}
}
System.out.println(list);
but the list by the end is empty.
Why does this happen?
You need to generate a new sub-Map when the desired size is reached, instead of cleaning the same sub-Map and placing it into the resulting list multiple times.
List<NavigableMap<String, List<Integer>>> list = new ArrayList<>();
NavigableMap<String, List<Integer>> submap = new TreeMap<>();
final int limit = 200;
for (Map.Entry<String, List<Integer>> entry : map.entrySet()) {
submap.put(entry.getKey(), entry.getValue());
if (submap.size() == limit) {
list.add(submap);
submap = new TreeMap<>();
}
}
Sidenote: it's more beneficial to use NavigableMap interface while working with a TreeMap because it offers many methods firtKey(), higherKey(), etc. that are not defined in the Map interface.

How to add a value to a list of values for a single key in a hashmap (Java)

I have written this:
HashMap<String, String> map1 = new HashMap<String, String>();
Map<String, ArrayList<String>> map2 = new HashMap<String, ArrayList<String>>();
i am trying to allow more then 1 value for each key in a hashmap. so if the first key is '1', i want to allow '1' to be paired with values '2' and '3'.
so it be like:
1 --> 2
|--> 3
but when I do:
map2.put(key, value);
it gives error that says "incompatible types" and it can not be converted to ArrayList and it says the error is at the value part of the line.
If you are using Java 8, you can do this quite easily:
String key = "someKey";
String value1 = "someValue1";
String value2 = "someValue2";
Map<String, List<String>> map2 = new HashMap<>();
map2.computeIfAbsent(key, k -> new ArrayList<>()).add(value1);
map2.computeIfAbsent(key, k -> new ArrayList<>()).add(value2);
System.out.println(map2);
The documentation for Map.computeIfAbsent(...) has pretty much this example.
In map2 you need to add ArrayList (you declared it as Map<String, ArrayList<String>> - the second one is the value type) only, that's why it gives you incompatible types.
You would need to do initialize the key with an ArrayList and add objects to it later:
if (!map2.containsKey(key)) {
map2.put(key, new ArrayList<String>());
}
map2.get(key).add(value);
Or you could use Multimap from guava, then you can just map2.put and it won't overwrite your values there but add to a list.
You are little bit away from what you are trying to do.
Map<String, ArrayList<String>> map2 = new HashMap<String, ArrayList<String>>();
this will allow only String as key and an ArrayList as value. So you have to try something like:
ArrayList<String> value=new ArrayList<String>();
value.add("2");
value.add("3");
map2.put("1", value);
When retrieving you also have to follow ans opposite procedure.
ArrayList<String> valueTemp=map2.get("1");
then you can iterate over this ArrayList to get those values ("2" and "3");
Try like this. //use list or set.. but set avoids duplicates
Map<String, Set<String>> map = new HashMap<>();
Set<String> list = new HashSet<>();
// add value to the map
Boolean b = map.containsKey(key);
if (b) {
map.get(key).addAll(list);
} else
map.put(key, list);
}
You can not add different values in same key in Map. Map is override the value in that key. You can do like this way.
Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>();
ArrayList<String> list=new ArrayList<String>();
list.add("2");
list.add("3");
map.put("1", list);
first add value in array list then put into map.
It is all because standard Map implementations in java stores only single pairs (oneKey, oneValue). The only way to store multiple values for a particular key in a java standard Map is to store "collection" as value, then you need to access this collection (from Map) by key, and then use this collection "value" as regular collection, in your example as ArrayList. So you do not put something directly by map.put (except from creating the empty collection), instead you take the whole collection by key and use this collection.
You need something like Multimap, for example:
public class Multimap<T,S> {
Map<T, ArrayList<S>> map2 = new HashMap<T, ArrayList<S>>();
public void add(T key, S value) {
ArrayList<T> currentValuesForGivenKey = get(key);
if (currentValuesForGivenKey == null) {
currentValuesForGivenKey = new ArrayList<T>();
map2.get(key, currentValuesForGivenKey);
}
currentValuesForGivenKey.add(value);
}
public ArrayList<S> get(T key) {
ArrayList<String> currentValuesForGivenKey = map2.get(key);
if (currentValuesForGivenKey == null) {
currentValuesForGivenKey = new ArrayList<S>();
map2.get(key, currentValuesForGivenKey);
}
return currentValuesForGivenKey;
}
}
then you can use it like this:
Multimap<String,String> map2 = new Multimap<String,String>();
map2.add("1","2");
map2.add("1","3");
map2.add("1","4");
for (String value: map2.get("1")) {
System.out.println(value);
}
will print:
2
3
4
it gives error that says "incompatible types" and it can not be converted to ArrayList and it says the error is at the value part of the line.
because, it won't automatically convert to ArrayList.
You should add both the values to list and then put that list in map.

What is the best practices to merge two maps

How can I add a new map to existing map. The maps have the same type Map<String, Integer>. If the key from new map exists in the old map the values should be added.
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
//Data added
//Now what is the best way to iterate these maps to add the values from both?
By add, I assume you want to add the integer values, not create a Map<String, List<Integer>>.
Before java 7, you'll have to iterate as #laune showed (+1 to him). Otherwise with java 8, there is a merge method on Map. So you could do it like this:
Map<String, Integer> oldMap = new TreeMap<>();
Map<String, Integer> newMap = new TreeMap<>();
oldMap.put("1", 10);
oldMap.put("2", 5);
newMap.put("1", 7);
oldMap.forEach((k, v) -> newMap.merge(k, v, (a, b) -> a + b));
System.out.println(newMap); //{1=17, 2=5}
What it does is that for each key-value pair, it merges the key (if it's not yet in newMap, it simply creates a new key-value pair, otherwise it updates the previous value hold by the existing key by adding the two Integers)
Also maybe you should consider using a Map<String, Long> to avoid overflow when adding two integers.
for( Map.Entry<String,Integer> entry: newMap.entrySet() ) {
// get key and value from newMap and insert/add to oldMap
Integer oldVal = oldMap.get( entry.getKey() );
if( oldVal == null ){
oldVal = entry.getValue();
} else {
oldVal += entry.getValue();
}
newMap.put( entry.getKey(), oldVal );
}
Hope that this is what you meant

Java: Sorting a Map, Map<Long,Map<String, Data>> based on the inner map

I am new to java and is still in the learning phase.
I have a structure
Map<Long, Map<String, Data>> mapData
Data has 2 fields time and distance
and the Map has a time which is a Long field and map with Identifier and Data
the structure looks like this
{190001919 = {[1= [data1], 2=[data2], 3=[data3]},
190001920={[1=[data4], 2=[data5], 3=[data6]},
1900019121= {[1=[data7], 2=[data8], 3=[data9]}}
and then convert it into a map - Map<String,List<Data>> mpData with
idenifier as key and values as the values where there the identifier was the same.
like
{1= [data1,data4,data7], 2= [data2,data5,data8],3= [data3,data6,data9]}
Could some one please help me?
Update:
With the below code, I get
{1= [data7,data7,data7], 2= [data8,data8,data8],3= [data9,data9,data9]}
instead of
{1= [data1,data4,data7], 2= [data2,data5,data8],3= [data3,data6,data9]}
Code:
public static Map<Long, Map<String, Data>> listData;
public static Map<String, List<Data>> mapData;
public convertMapData(Map<Long, Map<String, Data>> array) {
listData = new HashMap();
listData = array;
mapData = new HashMap<>();
Iterator it = listData.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Long, Map<String, Data>> pairs = (Map.Entry) it
.next();
Long keyValue = pairs.getKey();
Map inter = pairs.getValue();
Iterator it2 = inter.entrySet().iterator();
while (it2.hasNext()) {
Map.Entry<String, Data> pairs_2 = (Map.Entry) it2
.next();
String identifierK = pairs_2.getKey();
Data resultV = pairs_2.getValue();
if (!(mapData.containsKey(identifierK))) {
mapData.put(identifierK, new ArrayList<Data>());
}
mapData.get(identifierK).add(resultV);
}
}
}
Define Map<String,List<Data>> listData = new HashMap<String, List<Data>>();
Iterate over mapData's values (seems you don't use the keys of that map).
For every value of mapData, which again is a map, iterate over the entrySet, which gives you key (a String, lets call it K) and value (a Data object, lets call it V) of every entry.
Check if your listData already has a key like K (using containsKey()) and if not, add one, using listData.put(K, new ArrayList<Data>())
add V to the list that's stored for the key: listData.get(K).add(V)
That's all. As Rohit Jain commented, you'll not need a list around the listData map.
Try this:
public Map<String, List<Data>> convert(Map<Long, Map<String, Data>> array) {
Map<String, List<Data>> result = new HashMap<String, List<Data>>();
for (Map<String, Data> inter : array.values()) {
for (Map.Entry<String, Data> entry : inter.entrySet()) {
String k = entry.getKey();
String v = entry.getValue();
if (!result.containsKey(k)) {
result.put(k, new ArrayList<Data>());
}
result.get(k).add(v);
}
}
return result;
}

How does one convert a HashMap to a List in Java?

In Java, how does one get the values of a HashMap returned as a List?
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put (1, "Mark");
map.put (2, "Tarryn");
List<String> list = new ArrayList<String>(map.values());
for (String s : list) {
System.out.println(s);
}
Assuming you have:
HashMap<Key, Value> map; // Assigned or populated somehow.
For a list of values:
List<Value> values = new ArrayList<Value>(map.values());
For a list of keys:
List<Key> keys = new ArrayList<Key>(map.keySet());
Note that the order of the keys and values will be unreliable with a HashMap; use a LinkedHashMap if you need to preserve one-to-one correspondence of key and value positions in their respective lists.
Basically you should not mess the question with answer, because it is confusing.
Then you could specify what convert mean and pick one of this solution
List<Integer> keyList = Collections.list(Collections.enumeration(map.keySet()));
List<String> valueList = Collections.list(Collections.enumeration(map.values()));
Collection Interface has 3 views
keySet
values
entrySet
Other have answered to to convert Hashmap into two lists of key and value. Its perfectly correct
My addition: How to convert "key-value pair" (aka entrySet)into list.
Map m=new HashMap();
m.put(3, "dev2");
m.put(4, "dev3");
List<Entry> entryList = new ArrayList<Entry>(m.entrySet());
for (Entry s : entryList) {
System.out.println(s);
}
ArrayList has this constructor.
Solution using Java 8 and Stream Api:
private static <K, V> List<V> createListFromMapEntries (Map<K, V> map){
return map.values().stream().collect(Collectors.toList());
}
Usage:
public static void main (String[] args)
{
Map<Integer, String> map = new HashMap<>();
map.put(1, "one");
map.put(2, "two");
map.put(3, "three");
List<String> result = createListFromMapEntries(map);
result.forEach(System.out :: println);
}
If you only want it to iterate over your HashMap, no need for a list:
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put (1, "Mark");
map.put (2, "Tarryn");
for (String s : map.values()) {
System.out.println(s);
}
Of course, if you want to modify your map structurally (i.e. more than only changing the value for an existing key) while iterating, then you better use the "copy to ArrayList" method, since otherwise you'll get a ConcurrentModificationException. Or export as an array:
HashMap<Integer, String> map = new HashMap<Integer, String>();
map.put (1, "Mark");
map.put (2, "Tarryn");
for (String s : map.values().toArray(new String[]{})) {
System.out.println(s);
}
If you wanna maintain the same order in your list, say:
your Map looks like:
map.put(1, "msg1")
map.put(2, "msg2")
map.put(3, "msg3")
and you want your list looks like
["msg1", "msg2", "msg3"] // same order as the map
you will have to iterate through the Map:
// sort your map based on key, otherwise you will get IndexOutofBoundException
Map<String, String> treeMap = new TreeMap<String, String>(map)
List<String> list = new List<String>();
for (treeMap.Entry<Integer, String> entry : treeMap.entrySet()) {
list.add(entry.getKey(), entry.getValue());
}
I use usually map.values() to get values, then convert them to list
let say you have this Hashmap:
HashMap<String, Integer> map = new HashMap<>();
map.put("one", 1);
map.put("two", 2);
map.put("three", 3);
You can get values from the map, then convert them to a list in one code line like that:
List<Integer> values = map.values().stream()
.collect(Collectors.toList());

Categories