How do I convert a Map to List in Java? - java

How do I convert a Map<key,value> to a List<value>? Should I iterate over all map values and insert them into a list?

List<Value> list = new ArrayList<Value>(map.values());
assuming:
Map<Key,Value> map;

The issue here is that Map has two values (a key and value), while a List only has one value (an element).
Therefore, the best that can be done is to either get a List of the keys or the values. (Unless we make a wrapper to hold on to the key/value pair).
Say we have a Map:
Map<String, String> m = new HashMap<String, String>();
m.put("Hello", "World");
m.put("Apple", "3.14");
m.put("Another", "Element");
The keys as a List can be obtained by creating a new ArrayList from a Set returned by the Map.keySet method:
List<String> list = new ArrayList<String>(m.keySet());
While the values as a List can be obtained creating a new ArrayList from a Collection returned by the Map.values method:
List<String> list = new ArrayList<String>(m.values());
The result of getting the List of keys:
Apple
Another
Hello
The result of getting the List of values:
3.14
Element
World

Using the Java 8 Streams API.
List<Value> values = map.values().stream().collect(Collectors.toList());

map.entrySet() gives you a collection of Map.Entry objects containing both key and value. you can then transform this into any collection object you like, such as new ArrayList(map.entrySet());

a list of what ?
Assuming map is your instance of Map
map.values() will return a Collection containing all of the map's values.
map.keySet() will return a Set containing all of the map's keys.

I guess you want to convert the values contained in the Map to a list? Easiest is to call the values() method of the Map interface. This will return the Collection of value objects contained in the Map.
Note that this Collection is backed by the Map object and any changes to the Map object will reflect here. So if you want a separate copy not bound to your Map object, simply create a new List object like an ArrayList passing the value Collection as below.
ArrayList<String> list = new ArrayList<String>(map.values());

Map<String, Integer> map = new HashMap<String, Integer>();
map.put("java", 20);
map.put("C++", 45);
Set <Entry<String, Integer>> set = map.entrySet();
List<Entry<String, Integer>> list = new ArrayList<Entry<String, Integer>>(set);
we can have both key and value pair in list.Also can get key and value using Map.Entry by iterating over list.

If you want to ensure the values in the resultant List<Value> are in the key-ordering of the input Map<Key, Value>, you need to "go via" SortedMap somehow.
Either start with a concrete SortedMap implementation (Such as TreeMap) or insert your input Map into a SortedMap before converting that to List. e.g.:
Map<Key,Value> map;
List<Value> list = new ArrayList<Value>( new TreeMap<Key Value>( map ));
Otherwise you'll get whatever native ordering the Map implementation provides, which can often be something other than the natural key ordering (Try Hashtable or ConcurrentHashMap, for variety).

// you can use this
List<Value> list = new ArrayList<Value>(map.values());
// or you may use
List<Value> list = new ArrayList<Value>();
for (Map.Entry<String, String> entry : map.entrySet())
{
list.add(entry.getValue());
}

Map<String, String > map = new HapshMap<String, String>;
map.add("one","java");
map.add("two", "spring");
Set<Entry<String, String>> set = map.entrySet();
List<Entry<String, String>> list = new ArrayList<Entry<String, String>> (set);
for(Entry<String, String> entry : list) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
}

Here's the generic method to get values from map.
public static <T> List<T> ValueListFromMap(HashMap<String, T> map) {
List<T> thingList = new ArrayList<>();
for (Map.Entry<String, T> entry : map.entrySet()) {
thingList.add(entry.getValue());
}
return thingList;
}

public List<Object> convertMapToList(Map<Object, Object> map){
return new ArrayList<>(map.values());
}

If you want an immutable copy of the values:
List<Value> list = List.copyOf(map.values())

Related

Sort every Map in List by Set of keys

I have List of LinkedHashMap like List<Map<String, String>>. Every Map has the same number of elements and every Map has the same keys.
The second element is LinkedHashSet<String> - set of keys.
Now I would like to order every Map from List by keys. Sort ordering is in LinkedHashSet<String>.
My attempt is iterate by List<Map<String, String>>. For every Map create new Map and iterate by Set. To the new Map put key and value from old Mapwhere key is taken from Set. In code:
private List<Map<String, String>> sort(List<Map<String,String> result, LinkedHashSet<String> keys){
List<Map<String, String>> sortedResult = new LinkedList<>();
result.forEach(map -> {
Map<String, String> sortedMap = new LinkedHashMap<>();
keys.forEach(key -> {
sortedMap.put(key, map.get(key));
});
sortedResult.add(sortedMap);
});
return sortedResult;
}
I think it is a little bit complicated and in my opinion there exsists better way to do that.
You have a LinkedHashMap which tries to maintain only the order of insertion of keys, not the natural-ordering of keys. One thing you can do is to maintain a list of keys outside the map and sort them and re-insert the <key,value> pairs as per the order of the sorted list of keys. So it seems you are already doing this in your code by having an order defined by LinkedHashSet.
The other simple approach is:
If you want an ordered map by keys, you most probably need a TreeMap, insertion into this map maintains the natural ordering of keys and you can construct a treemap from an existing map.
private List<Map<String, String>> sort(List<Map<String,String> result) {
List<Map<String, String>> sortedResult = new LinkedList<>();
for ( Map<String, String> m : result )
sortedResult.add(new TreeMap(m)));
return sortedResult;
}
BTW, Local variables referenced from a lambda expression must be final
There are a couple of things I would change:
The argument name "result" is misleading. People going over the code quickly will think this is the returned result. I would change it to "unsortedMaps" or something similar
Each Map shouldn't affect the other so instead of result.forEach you could use result.parallelStream().forEach to make every map sorted in it's own thread. You will need to make insertion to list itself thread safe (either surronding "sortedResult.add(sortedMap" with synchronized statment or use a thread-safe list implementation. All this doesn't guarantee improvement in performance. It depends on many variants such as the size of the collections and number of cores. Test it to find out.
There are a lot of details in this function. I would extract the part dealing with each map to a seperate function
Here is the result (didn't test the code so can't gurentee correctness. Needless to say unit-tests are always the way to go):
private List<Map<String, String>> sort(List<Map<String,String>> unsortedMaps, LinkedHashSet<String> keys){
List<Map<String, String>> sortedResult = new LinkedList<>();
unsortedMaps.parallelStream().forEach(map -> {
Map<String, String> sortedMap = getSortedMap(keys, map);
synchronized (sortedResult) {
sortedResult.add(sortedMap);
}
});
return sortedResult;
}
private Map<String, String> getSortedMap(LinkedHashSet<String> keys, Map<String, String> map) {
Map<String, String> sortedMap = new LinkedHashMap<>();
keys.forEach(key -> {
sortedMap.put(key, map.get(key));
});
return sortedMap;
}
To complete SomeDude answer, if the natural order isn't enough for your need, you can try to specify a Comparator to the TreeMap :
private List<Map<String, String>> sort(List<Map<String,String>> mapList, Set<String> keys){
List<String> keysList = new ArrayList<>(keys);
return mapList.stream().map(map -> copyAndReOrderMap(map, keysList)).collect(Collectors.toList());
}
private Map<String, String> copyAndReOrderMap(Map<String, String> map, List<String> keysList) {
Map<String, String> orderedMap = new TreeMap<>((key1, key2) -> Integer.compare(keysList.indexOf(key1), keysList.indexOf(key2)));
orderedMap.putAll(map);
return orderedMap;
}
NB: Unless you deal with very large maps, i don't see why you would want to sort each map in a separate Thread.

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.

How to print all the values for a key in HashMap in java

Map<String, String> map = new HashMap<String, String>();
map.put("1", "xyz");
map.put("1", "abc");
map.put("1", "cde");
map.put("2", "err");`
`
for the above map I want to get all the values associated with the key 1. Expected output.
Key:: 1 values are:: xyz, abc, cde
Order of the values doesn't important.
In a Map the key should always be unique. If you associate a new value to an existing key, it will overwrite the value of the existing entry.
You might need to check the interface for Map#put(K, V) method.
If the map previously contained a mapping for the key, the old value
is replaced by the specified value.
So in your case your map will always have "cde" as the value for the key "1".
Use MultiMap
MultiMap mapValue = new MultiValueMap();
mapValue.put("1", "xyz");
mapValue.put("1", "abc");
mapValue.put("1", "cde");
mapValue.put("2", "err");
System.out.println("Map : " + mapValue);
Output: Map : {2=[err], 1=[xyz, abc, cde]}
A map can not have duplicate keys.
If you want to implement what you describe in question. First you need to use multimaps
What you are doing is wrong.
Map doesn't allow duplicates.
So one key -----------> one value
If you see docs of put()
Associates the specified value with the specified key in this map (optional operation). If the map previously contained a mapping for the key, the old value is replaced by the specified value. (A map m is said to contain a mapping for a key k if and only if m.containsKey(k) would return true.)
You can print the values of each key and value like
Ex:
Map<String, String> map = new HashMap<String, String>();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}
In Map you can't have duplicate keys. so In your case final value put for key 1. "cde" will remain in Map
You can do some thing like following to achive what you are expecting
Map<String, List<String>> map = new HashMap<>();
List<String> list=new ArrayList<>();
List<String> list1=new ArrayList<>();
list.add("xyz");
list.add("abc");
list.add("cde");
list1.add("err");
map.put("1", list);
map.put("2",list1);
System.out.println(map.get("1"));
HashMap::put overrides the old value associated with the key. You have to put a List in each map entry and insert new values in the appropriate list.
From the java documentation about HashMap.put(K key, V value) method:
Associates the specified value with the specified key in this map. If the map previously contained a mapping for the key, the old value is replaced.
So you can't do that.
This is impossible, a map is called a map because it maps one key value to a value. Multiple keys can map to the same value but not the other way around.
What you probably want is a map which maps to a List<String> instead:
final Map<String, List<String>> map = new HashMap<>();
if (map.get("1") == null) {
map.put("1", new ArrayList<String>());
}
map.get("1").add("xyz");
// ...
A helper function for adding might be convenient
public static <K, V> void add(final K key, final V value, final Map<K, List<V>> map)
{
if (map.get(key) == null) {
map.put(key, new ArrayList<V>());
}
map.get(key).add(value);
}
You can not do this with this type of Map. The key in map must be unique.
To be able to do that you should declare a map, where key is string but values are collections of Strings.
Map<String,Collection<String>> map = new HashMap<String,Collection<String>>();
The to list values from it you can do this
for(String valueOfKey : map.get("key") {
//print or something else
}
Note that to add some values to it you must first check that key is already stored and if not then fist declare a collection.
if(map.contains("key") == false) {
map.put(new ArrayList<String>());
}
map.get("key").add("value");
As this is well know design you might be interest in guava framework and Multimap
The benefit of this class is that it already has implemented the logic how to add and retrieve values from it.
You could do something like:
for (String k : map.keySet())
System.out.println(k);
This would print the keys in the HashMap, but without any guarantees on order.
You can not have duplicate key for a hash map see the below S.O for What happens for duplicate keys in HashMap

Sorting Guava table on values

Is there any possible way to do that? The expecting effect would be that rowMap and columnMap entry values would be sorted by value.
The problem is that I cannot create a comparator without the underlying maps in Table.
Table table = TreeBasedTable.create(?,?);
Map<String, Map<String, String>> rowMap = table.rowMap();
Map<String, String> thisMapShouldBeSortedByValues = rowMap.get(smth);
Map<String, Map<String, String>> columnMap = table.columnMap();
Map<String, String> thisMapShouldBeSortedByValues = columnMap.get(smth);
Now I always have to sort rowMap and columnMap afterwards and allocate new TreeMaps on that.
First of all, I am assuming that by thisMapShouldBeSortedByValues, you mean thisMapShouldBeSortedByKeys
TreeBasedTable extends RowSortedTable, so the table is only sorted by it's rows, not its columns. Calling table.columnMap() gives you an unordered Map<C, Map<R, V>.
Since it is sorted by rows, the table.rowMap returns a SortedMap<R, Map<C, V>>. So the map is sorted on it's row keys, but the Map<C, V> value is an unsorted map, hence why calls to rowMap.get() returns an unordered map.
The SortedMap you are trying to get from calling table.rowMap(), and then rowMap.get(), can be obtained by instead calling table.rowKeySet() and table.row(R rowKey) like so (You build the map you originally wanted to get by calling table.rowMap():
ImmutableSortedMap.Builder<String, SortedMap<String, String>> builder = ImmutableSortedMap.builder();
for (String rowKey : table.rowKeySet()){
builder.put(rowKey, table.row(rowKey)) ;
}
SortedMap<String, <SortedMap<String, String>> thisMapIsSortedByKeys = builder.build();

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