I have an Map<String,Integer> which is sorted by value like that
public void sortList(Map<String,Integer> map){
set = map.entrySet();
list = new ArrayList<Map.Entry<String, Integer>>(set);
Collections.sort( list, (o1, o2) -> (o2.getValue()).compareTo( o1.getValue() ));
}
I need to copy all values to new list
word_used = new ArrayList<Integer>(map.values());
but it saves in non-sorted order
When you sort that list you created from the entrySet, it doesn't change the order of the entries in the original Map. You'll have to return the list from your sortList method if you want a List of the sorted values.
map.values() will not return the values sorted, since the values are not kept in any specific order in the Map. Some Map implementations (such as TreeMap) keep the keys sorted, but not the values.
First extract the list, sort it and then create a new list with it.
List<Integer> tmp = map.values();
Collections.sort(tmp);
word_used = new ArrayList<Integer>(tmp);
java-8
word_used = new ArrayList<Integer>(map.values()
.stream()
.sorted()
.collect(Collectors.toList()));
Related
I have this scenario where I have to sort listA based on the order of elements in listB.
But the problem I am facing is that if there is that if listA contains an element which is not defined in the listB then the sort result has all contents of listA sorted as per order in listB but the element which is not defined in listB as the first element.
Example
Input:
listA = [us,au,in,gb]
listB = [au,us,in] // sort order list
Current Output:
listA = [gb,au,us,in] // result after sorting
Expected Output:
listA = [au,us,in,gb] // result after sorting
Here, since "gb" is not present in the sort list listB, the result has "gb" as the first element, but I want that to be the last element.
I am using the below code to sort the listA:
listA.sort(Comparator.comparingInt(listB::indexOf));
It would be performance wise to generate a HashMap associating the string elements with the corresponding indices (i.e. Map<String,Integer>), instead of relaying on List.indexOf() method which performs iteration under the hood. And then define a Comparator based on this Map.
In order to place the elements that not are not present in the listB at the end of the sorted list, we can make use of the method Map.getOrDefault() providing the size of the map as a default value.
List<String> listA = new ArrayList<>(List.of("us","au","in","gb"));
List<String> listB = new ArrayList<>(List.of("au","us","in"));
Map<String, Integer> order = IntStream.range(0, listB.size())
.boxed()
.collect(Collectors.toMap(
listB::get,
Function.identity()
));
Comparator<String> comparator = Comparator.comparingInt(s -> order.getOrDefault(s, order.size()));
listA.sort(comparator);
System.out.println(listA);
Output:
[au, us, in, gb]
In case in you want to preserve the initial order of the elements in listA that are not present in the listB (i.e. group them at the very end of the list according to their initial ordering), you can generate an additional Map. This time based on the listA, which associate each element like gb with a unique Value greater or equal to the size of listB:
List<String> listA = new ArrayList<>(List.of("fr","us","nl","au","in","gb"));
List<String> listB = new ArrayList<>(List.of("au","us","in"));
Map<String, Integer> order = IntStream.range(0, listB.size())
.boxed()
.collect(Collectors.toMap(
listB::get,
Function.identity()
));
Map<String, Integer> resolver = IntStream.range(0, listA.size())
.filter(i -> !order.containsKey(listA.get(i))) // to reduce the size of the Map
.boxed()
.collect(Collectors.toMap(
listA::get,
i -> i + order.size()
));
Comparator<String> comparator = Comparator.comparingInt(
s -> order.getOrDefault(s, resolver.get(s))
);
listA.sort(comparator);
Output:
[au, us, in, fr, nl, gb] // the order of "fr","nl","gb" is preserved
just a quick hack but,
public class ExList extends ArrayList<String> {
public int indexOf(String s) {
int returnValue = super.indexOf(s);
if ( returnValue == -1 ) {
return size();
}
return returnValue;
}
}
and create listB as instance of ExList, it would give you a desired result.
How can we order the content of a map by comparing its values instead of the value of its keys? For example, how can we implement a method sortByAbsoluteValue that orders the map entries from the one with highest absolute value to lowest absolute value:
HashMap<String,Integer> hashmap=new HashMap<String,Integer>();
hashmap.put("product5",100);
hashmap.put("product6",-20);
hashmap.put("product3",10);
hashmap.put("product4",5);
hashmap.put("product1",15);
hashmap.put("product2",-40);
hashmap.put("product9",0);
hashmap.put("product7",70);
hashmap.put("product8",30);
Map<String, Integer> map = sortByAbsoluteValue(hashmap);
Where map.toString() would output
{product5=100, product7=70, product2=-40, product8=30, product6=-20, product1=15, product3=10, product4=5, product9=0}
While I agree with some of the comments hinting that a list is better suited when looking for sorted results, Java does allow some maps like the TreeMap to be sorted using Comparator<> functions.
Unfortunately, Maps are always sorted by key, but luckily, Java also provides LinkedHashMap which maintain their insertion order.
So the trick here is to first sort using the Comparator in a TreeMap using the value as a key, and then insert the sorted result to a LinkedHashMap:
private LinkedHashMap<String, Integer> sortByAbsoluteValue(Map<String, Integer> unsorted)
{
// assemble the comparator function
Comparator<Integer> sortedByAbsValue = Comparator.comparingInt(Math::abs);
Comparator<Integer> sortedByAbsValueReversed = sortedByAbsValue.reversed();
// group by value, sorting using the custom comparator
TreeMap<Integer, List<Map.Entry<String, Integer>>> sorted = new TreeMap<>(sortedByAbsValueReversed);
sorted.putAll(unsorted.entrySet().stream().collect(Collectors.groupingBy(Map.Entry::getValue)));
// assemble back into a map that maintains insertion order
return sorted.entrySet()
.stream()
.flatMap(kv -> kv.getValue().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (a, b) -> b, LinkedHashMap::new));
}
I have a Map<Integer, Set<Integer>> and i want to get the list of keys as an ArrayList in an increasing order.
So for example my map:
Key|Value
2--->set1
1--->set2
5--->set3
I want to get the arraylist : [1,2,5]
public class Example {
public static void main( String[] args ) {
Map<Integer,Set<Integer>> map = new HashMap<>();
Set<Integer> set1 = Stream.of(1,2,3).collect(Collectors.toSet());
Set<Integer> set2 = Stream.of(1,2,3).collect(Collectors.toSet());
Set<Integer> set3 = Stream.of(1,2,3).collect(Collectors.toSet());
map.put(2,set1);
map.put(1,set2);
map.put(5,set3);
//what i have done:
List<Integer> list = map.keySet()
.stream()
.collect(Collectors.toCollection(ArrayList::new));
list.sort((a,b)->a>b?b:a);
System.out.println(list);
}
}
This example do what i want, but i'm looking for a solution that make the sorting in the time of collecting the elements?
use the sorted method:
List<Integer> list = map.keySet()
.stream()
.sorted()
.collect(Collectors.toCollection(ArrayList::new));
Even better, just change HashMap to TreeMap like this:
Map<Integer,Set<Integer>> map = new TreeMap<>();
Quoting from docs "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 case of Integers you will have natural order:)
I have a simple map and need to create a list that is sorted based on the number in ascending order from a given list:
Map auto = new HashMap();
auto.put("Merc", 3);
auto.put("Citroen", 5);
auto.put("Opel", 10);
auto.put("BMW", 20);
List<String> given = new ArrayList<>();
given.add("Opel");
given.add("BMW");
given.add("Citroen");
So the given list needs to be sorted so that it will be in this order: Citroen, Opel, BMW. Was thinking of:
create another map then iterate through list
get number from first map
put the number as the key and the name as value in the new map
sort the map by key
iterate threw new map then add values to the list
This seems terrible :/, any suggestions and perhaps better data structures to use?
Using Java 8 you can do.
Map<String, Integer> auto = new HashMap<>();
auto.put("Merc", 3);
auto.put("Citroen", 5);
auto.put("Opel", 10);
auto.put("BMW", 20);
List<String> given = new ArrayList<>();
given.add("Opel");
given.add("BMW");
given.add("Citroen");
// to sort the selected elements.
given.sort(Comparator.comparing(auto::get));
// to sort all elements.
List<String> names = auto.entrySet().stream()
.sorted(Comparator.comparing(Map.Entry::getValue))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
Breaking this down
List<String> names =
// give the set of entries as a Stream.
auto.entrySet().stream()
// sort these entries, using the field returned by getValue()
.sorted(Comparator.comparing(Map.Entry::getValue))
// now sorted, turn each Entry into just the getKey()
.map(Map.Entry::getKey)
// now we have a stream of keys, turn this into a List<String>
.collect(Collectors.toList());
Collections#sort
Collections.sort(given, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
return auto.get(o1).compareTo(auto.get(o2));
}
});
Or with lambda:
Collections.sort(given, (o1, o2) -> auto.get(o1).compareTo(auto.get(o2)));
Java 8 null-safe solution inspired from multiple answers
given.sort(Comparator.comparing((s) -> auto.getOrDefault(s, Integer.MAX_VALUE)));
With Java 8, you could just do
given.sort(Comparator.comparing(auto::get));
...and it's just that one-liner. Or with the Guava library you could do
Collections.sort(given, Ordering.natural().onResultOf(Functions.forMap(auto)));
Create a Car class that implements Comparable and includes the name and priority.
Then you can sort lists with Collections.sort() directly.
Map<String,Integer> auto = new HashMap<String,Integer>();
auto.put("Merc", 3);
auto.put("Citroen", 5);
auto.put("Opel", 10);
auto.put("BMW", 20);
Set<Map.Entry<String,Integer>> set = auto.entrySet();
List<Map.Entry<String,Integer>> list = new ArrayList<Map.Entry<String,Integer>>(set);
Collections.sort(list,new Comparator<Map.Entry<String,Integer>>(){
#Override
public int compare(Entry<String, Integer> o1,
Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
Once you have List Objects of Map.Entry,you can extract key using Entry.getKey()
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())