Grouping and Double sorting List<Person> - java

I went through all the manuals out there and all SO questions but still unable to figure this out...
I have a List (integer represents age):
List<Person> people = Arrays.asList
(
new Person("bob", 10),
new Person("sue", 4),
new Person("tom", 37),
new Person("jim", 10),
new Person("boo", 4),
new Person("ekk", 53),
new Person("joe", 10)
);
I need to:
group the list by age,
sort by group sizes (descending),
sort by age (descending)
So using the example above the result would have to be like this:
{10=[bob, jim, joe],4=[sue, boo], 53=[ekk], 37=[tom]}
What I tried:
I tried with and without streams. I failed on both.
Note: I would lean toward no stream solution, because from my testing of the below code it seems like streams are much slower (I used System.nanotime()). These 3 operations will be done thousands of times each time, so it may make a slight difference.
Using streams here is what I did:
List<List<Person>> grpd = new ArrayList<>
(
people.stream()
.collect
(
groupingBy(Person::getAge, toList())
)
.values()
);
grpd = grpd.stream().sorted((a, b) -> Integer.compare(b.size(), a.size())).collect(toList());
No streams approach:
Map<Integer, List<Person>> grouped = new HashMap<>();
for (Person person : people)
{
if (grouped.containsKey(person._age))
{
grouped.get(person._age).add(person);
} else
{
List<Person> p = new ArrayList<>();
p.add(person);
grouped.put(person._age, p);
}
}
List<Map.Entry<Integer, List<Person>>> entries = new ArrayList<>(grouped.entrySet());
Collections.sort(entries, new Comparator<Map.Entry<Integer, List<Person>>>()
{
#Override
public int compare(Map.Entry<Integer, List<Person>> o1, Map.Entry<Integer, List<Person>> o2)
{
return Integer.compare(o2.getValue().size(), o1.getValue().size());
}
});
Map<Integer, List<Person>> sortedBySize = new LinkedHashMap<>();
for (Map.Entry<Integer, List<Person>> entry : entries)
{
sortedBySize.put(entry.getKey(), entry.getValue());
}
Problem:
I have no idea how to add the final sort on either case.
public class Person
{
public String _name;
public int _age;
public int getAge() { return _age; }
public Person(String name, int age)
{
_name = name;
_age = age;
}
#Override
public String toString()
{
return _name;
}
}

Use streams.
First, group them by age:
Map<Integer, List<Person>> groupedByAge =
people.stream().collect(groupingBy(Person::getAge));
Then sort the entries of this map:
Comparator<Map.Entry<Integer, List<Person>>> byCount = comparingInt(e -> e.getValue().size());
Comparator<Map.Entry<Integer, List<Person>>> byAge = comparingInt(Map.Entry::getKey);
Stream<Map.Entry<Integer, List<Person>>> sorted =
groupedByAge.entrySet().stream().sorted(byCount.reversed().thenComparing(byAge.reversed()));
Then just get the list out of there:
List<List<Person>> result = sorted.map(Map.Entry::getValue).collect(toList());
(You can put this all into a single expression, but I claim it is more readable broken out like this).

As you've also asked about a non-stream solution, here it is:
Map<Integer, List<Person>> grouped = new HashMap<>();
people.forEach(person -> grouped.computeIfAbsent(
person.getAge(),
k -> new ArrayList<>())
.add(person));
This groups by age. Now let's sort the entries, first by group size descending, then by age descending:
List<Map.Entry<Integer, List<Person>>> toSort = new ArrayList<>(grouped.entrySet());
toSort.sort(
Comparator.comparingInt((Map.Entry<Integer, List<Person>> e) -> e.getValue().size())
.reversed()
.thenComparingInt(Map.Entry.comparingByKey().reversed()));
Now, toSort is a sorted list of entries. You need to put those entries into a new map:
Map<Integer, List<Person>> sorted = new LinkedHashMap<>();
toSort.forEach(e -> sorted.put(e.getKey(), e.getValue()));
And sorted holds the result you want.

Since you were also looking for a non-stream solution:
public static Map<Integer, List<Person>> group(List<Person> people) {
Map<Integer, List<Person>> intermediateGrouping = new HashMap<>();
for (Person person : people) {
intermediateGrouping.computeIfAbsent(person.getAge(), k -> new ArrayList<>()).add(person);
}
Comparator<Entry<Integer, List<Person>>> byGroupSize = Entry.comparingByValue(Comparator.comparingInt(List::size));
Comparator<Entry<Integer, List<Person>>> byAge = Entry.comparingByKey();
List<Entry<Integer, List<Person>>> entries = new ArrayList<>(intermediateGrouping.entrySet());
entries.sort(byGroupSize.reversed().thenComparing(byAge.reversed()));
Map<Integer, List<Person>> result = new LinkedHashMap<>(entries.size());
for (Entry<Integer, List<Person>> entry : entries) {
result.put(entry.getKey(), entry.getValue());
}
return result;
}
Or if you prefer the result to be a List<List<Person>>:
public static List<List<Person>> group(List<Person> people) {
Map<Integer, List<Person>> intermediateGrouping = new HashMap<>();
for (Person person : people) {
intermediateGrouping.computeIfAbsent(person.getAge(), k -> new ArrayList<>()).add(person);
}
Comparator<Entry<Integer, List<Person>>> byGroupSize = Entry.comparingByValue(Comparator.comparingInt(List::size));
Comparator<Entry<Integer, List<Person>>> byAge = Entry.comparingByKey();
List<Entry<Integer, List<Person>>> entries = new ArrayList<>(intermediateGrouping.entrySet());
entries.sort(byGroupSize.reversed().thenComparing(byAge.reversed()));
List<List<Person>> result = new ArrayList<>(entries.size());
for (Entry<Integer, List<Person>> entry : entries) {
result.add(entry.getValue());
}
return result;
}

Try modifiying your sort comparator using the below implementation when the sizes are equal for a no streams approach
Collections.sort(entries, new Comparator<Map.Entry<Integer, List<Person>>>()
{
#Override
public int compare(Map.Entry<Integer, List<Person>> o1, Map.Entry<Integer, List<Person>> o2)
{
if(o1.getValue().size()<o2.getValue().size())
return 1;
else if(o1.getValue().size()>o2.getValue().size())
return -1;
else {
if( o1.getKey()< o2.getKey())
return 1;
else if(o1.getKey()>o2.getKey())
return -1;
else
return 0;
}
}
});
Let me know if it works on all your Test Cases

Related

Leaderboard displaying entire list instead of pagination

I have a list of users (stored in a properties file) that have a level. I sort the users by their level and then send the sorted list back to the guild. I paginate the list, but its still showing all of the users instead of just 10 per page.
Map<String, Integer> unsortedMap = new HashMap<String, Integer>();
for (String key : prop.stringPropertyNames()) {
String value = prop.getProperty(key);
unsortedMap.put(key, Integer.valueOf(value));
}
Map<String, Integer> sortedMap = sortByValue(unsortedMap);
EmbedBuilder eb = new EmbedBuilder();
eb.setTitle("aaaaaaaaaaaa");
ArrayList<Page> pages = new ArrayList<>();
for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
String key = entry.getKey();
int value = entry.getValue();
if (key.contains(".level")) {
User users = ctx.getJDA().retrieveUserById(key.replace(".level", ""), true).complete();
eb.addField(users.getName(), String.valueOf(value), false);
}
}
for (int i = 0; i < sortedMap.size(); i++){
pages.add(new InteractPage(eb.build()));
}
channel.sendMessageEmbeds((MessageEmbed) pages.get(0).getContent()).queue(success -> {
Pages.paginate(success, pages, true);
});
}
private static Map<String, Integer> sortByValue(Map<String, Integer> unsortedMap) {
List<Map.Entry<String, Integer>> list = new LinkedList<Map.Entry<String, Integer>>(unsortedMap.entrySet());
Collections.sort(list, new Comparator<Map.Entry<String, Integer>>() {
#Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return (o2.getValue().compareTo(o1.getValue()));
}
});
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Map.Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
Partition the for loop into smaller parts using the for loop. Initialize the int outside of the loop and then increment the int for every entry and then divide the int by how many items you want displayed on the list. Ex:
int i = 0;
for (Map.Entry<String, Integer> entry : sortedMap.entrySet()) {
i++;
if (i % 6 == 0) {
//add page here

Seeking Optimization Suggestions for Map-to-Map Conversion

I'm seeking feedback as to whether there's a more efficient approach than what I'm doing in my code shown at the bottom.
Basically, given this map:
Set<String> A_Set = new HashSet<>(Arrays.asList("1111", "2222", "5555"));
Set<String> B_Set = new HashSet<>(Arrays.asList("3333", "4444"));
Set<String> C_Set = new HashSet<>(Arrays.asList("6666"));
Set<String> D_Set = new HashSet<>(Arrays.asList("2222", "5555", "6666"));
Map<String, Set<String>> values = new HashMap<>();
values.put("A", A_Set);
values.put("B", B_Set);
values.put("C", C_Set);
values.put("D", D_Set);
which looks like this:
How do I create a Map<String, List<Boolean> map such that it looks like this:
In the most efficient way possible. My real Map has thousands of values per Set, but there are only ever 4 Sets (A, B, C, D).
Here's my current code. Can you think of a more efficient approach?
import java.util.*;
public class MapToMap {
public static void main(String[] args) {
Set<String> A_Set = new HashSet<>(Arrays.asList("1111", "2222", "5555"));
Set<String> B_Set = new HashSet<>(Arrays.asList("3333", "4444"));
Set<String> C_Set = new HashSet<>(Arrays.asList("6666"));
Set<String> D_Set = new HashSet<>(Arrays.asList("2222", "5555", "6666"));
Map<String, Set<String>> values = new HashMap<>();
values.put("A", A_Set);
values.put("B", B_Set);
values.put("C", C_Set);
values.put("D", D_Set);
Map<String, List<Boolean>> exists = new HashMap<>();
for (Map.Entry<String, Set<String>> v : values.entrySet()) {
for (String val : v.getValue()) {
if (exists.containsKey(val)) {
List<Boolean> list = exists.get(val);
list = addValue(v.getKey(), list);
exists.put(val, list);
} else {
List<Boolean> newList = new ArrayList<>(Arrays.asList(false, false, false, false));
newList = addValue(v.getKey(), newList);
exists.put(val, newList);
}
}
}
for (Map.Entry<String, List<Boolean>> s : exists.entrySet()) {
System.out.println(s);
}
}
private static List<Boolean> addValue(String key, List<Boolean> listToUse) {
List<Boolean> newList = new ArrayList<>();
if (Objects.equals("A", key)) {
newList.addAll(Arrays.asList(true, listToUse.get(1), listToUse.get(2), listToUse.get(3)));
} else if (Objects.equals("B", key)) {
newList.addAll(Arrays.asList(listToUse.get(0), true, listToUse.get(2), listToUse.get(3)));
} else if (Objects.equals("C", key)) {
newList.addAll(Arrays.asList(listToUse.get(0), listToUse.get(1), true, listToUse.get(3)));
} else if (Objects.equals("D", key)) {
newList.addAll(Arrays.asList(listToUse.get(0), listToUse.get(1), listToUse.get(2), true));
}
return newList;
}
}
Here's a solution using streams:
Map<String, List<Boolean>> exists = values.values()
.stream()
.flatMap(Set::stream)
.distinct()
.collect(Collectors.toMap(v -> v, v -> Stream.of("A", "B", "C", "D")
.map(k -> values.get(k).contains(v))
.collect(Collectors.toList())));
Ideone Demo

Java streams sum values of a List of Maps

i want to determine the of the "columns" in "rows" or or better: Build sum of a list of maps like List> rows
Is it somehow possible to sum all values of each distinct column? The function shall return a Map with the column as key and the sum of all values as value.
summMap.get("columname")
Let's assume i have the following list of maps:
List<Map<String, Long>> mapList = new ArrayList();
Map<String, Object> map1 = new HashMap<>();
Map<String, Object> map2 = new HashMap<>();
Map<String, Object> map3 = new HashMap<>();
map1.put("col1", 90);
map1.put("col2", 50);
map1.put("col3", 10);
map2.put("col1", 90);
map2.put("col2", 50);
map2.put("col3", 10);
map3.put("col1", 90);
map3.put("col2", 50);
map3.put("col3", 10);
mapList.add(map1);
mapList.add(map2);
mapList.add(map3);
Map<String, Long> sum = mapList.stream().distinct().sum() // Example
// result i'm awaiting/expecting
Long sumVal1 = sum.get("col1"); // 270
Long sumVal2 = sum.get("col2"); // 150
Long sumVal3 = sum.get("col3"); // 30
Long sumVal = sum.get("col1");
It’s as simple as
Map<String, Long> sum = mapList.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, Long::sum));
Holger has already provided a clean solution, but I think you can also try flatMap and groupingBy as:
Map<String, Long> sum = mapList.stream().flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, summingLong(Map.Entry::getValue)));
The whole solution to your question:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.*;
public class ListMapSum {
public static void main(String... args) {
List<Map<String, Long>> mapList = new ArrayList();
Map<String, Long> map1 = new HashMap<>();
Map<String, Long> map2 = new HashMap<>();
Map<String, Long> map3 = new HashMap<>();
map1.put("col1", 90L);
map1.put("col2", 50L);
map1.put("col3", 10L);
map2.put("col1", 90L);
map2.put("col2", 50L);
map2.put("col3", 10L);
map3.put("col1", 90L);
map3.put("col2", 50L);
map3.put("col3", 10L);
mapList.add(map1);
mapList.add(map2);
mapList.add(map3);
Map<String, Long> sum = mapList.stream().flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, summingLong(Map.Entry::getValue)));
Long sumVal1 = sum.get("col1"); // 270
Long sumVal2 = sum.get("col2"); // 150
Long sumVal3 = sum.get("col3"); // 30
}
}
This doesn't support parallel execution, but could do by modifying the last argument in reduce:
private static Map<String, Long> reduceLongs(List<Map<String, Long>> maps) {
return maps.stream()
.flatMap(map -> map.entrySet().stream())
.reduce(new HashMap<>(), (map, e) -> {
map.compute(e.getKey(), (k ,v) -> v == null ? e.getValue() : e.getValue() + v);
return map;
}, (m1, m2) -> { throw new UnsupportedOperationException(); });
}
And a passing test:
final List<Map<String, Long>> maps = new ArrayList<>();
Map<String, Long> map1 = new HashMap<>();
Map<String, Long> map2 = new HashMap<>();
map1.put("col1", 90L);
map1.put("col2", 50L);
map2.put("col1", 90L);
map2.put("col2", 50L);
map2.put("col3", 100L);
maps.add(map1);
maps.add(map2);
final Map<String, Long> sums = reduceLongs(maps);
assertEquals(180L, sums.get("col1").longValue());
assertEquals(100L, sums.get("col2").longValue());
assertEquals(100L, sums.get("col3").longValue());
This gives the same answer even after changing the values
Here is the simple solution, it will give the result as per your requirement:
List<Map<String, Long>> mapList = new ArrayList();
Map<String, Long> map1 = new HashMap<>();
Map<String, Long> map2 = new HashMap<>();
Map<String, Long> map3 = new HashMap<>();
map1.put("col1", 90L);
map1.put("col2", 50L);
map1.put("col3", 10L);
map2.put("col1", 90L);
map2.put("col2", 50L);
map2.put("col3", 10L);
map3.put("col1", 90L);
map3.put("col2", 50L);
map3.put("col3", 10L);
mapList.add(map1);
mapList.add(map2);
mapList.add(map3);
Map<String, Long> sum = new HashMap<>();
mapList.forEach(map -> map.keySet().forEach(
s -> {
mapList.stream()
.collect(Collectors.groupingBy(foo -> s,
Collectors.summingLong(foo -> map.get(s)))).forEach(
(id, sumTargetCost) ->
sum.put(s, sumTargetCost)
);
}
));
Long sumVal1 = sum.get("col1"); // 270
Long sumVal2 = sum.get("col2"); // 150
Long sumVal3 = sum.get("col3"); // 30
System.out.println("SumVal1: " + sumVal1 + ", SumVal2: " + sumVal2 + ", SumVal3: " + sumVal3);

What is a better way to break java list in Map of Maps?

We have
List<persons> persons;
and we need
Map<age,Map<income,Person>> results
the way I am doing it now is :
ages.stream().forEach(a -> {
Map<Integer,Person> tmpMap = new HashMap<>();
incomes.stream().forEach(i -> {
Person p = persons.stream().filter(
u -> u.getAge() == a.getAge() &&
u.getIncome() == i.getIncome())
.findAny().orElse(null);
tmpMap.put(i.getIncome(), p);
});
returns.put(a.getAge(),tmpMap);
});
it seems like there should be a better way of doing this.
This looks like it works.
List<Person> people = Arrays.asList(
new Person("One", 21, 100),
new Person("Two", 21, 75),
new Person("Three", 42, 100),
new Person("Four", 42, 120),
new Person("Five", 9, 100)
);
Map<Integer, Map<Integer, Person>> map = people.stream()
// Gather all ages into a Map<Age,List<Person>>
.collect(Collectors.groupingBy(Person::getAge))
// Walk that transient Map.
.entrySet().stream()
.collect(Collectors.toMap(
// Key is the age.
Map.Entry::getKey,
// Value is a Map<income,person>
e -> e.getValue()
// Roll each of the same age into a Map<Income,Person>
.stream().collect(
Collectors.toMap(
// Key is income.
Person::getIncome,
// Value is the Person.
Function.identity()
))));
I roll your list into a Map<Age,List<Person>> using a groupingBy and then stream it's entrySet and collect that into the final form.
This will fail if two people of the same age have the same income because that will violate the inner Map. Use Alexander's suggestion if you are happy with the natural enhancement of generating a Map<Integer, Map<Integer, List<Person>>>.
Added
#Holger has pointed out in a comment that this can be done in a much simpler and more elegant way. Please use this form instead/
Map<Integer, Map<Integer, Person>> map2 = people.stream()
.collect(
Collectors.groupingBy(
Person::getAge,
Collectors.toMap(Person::getIncome, Function.identity())));
FYI - Here's the Person class I used. Note the equals and hashcode are implemented.
class Person {
private final String name;
private final int age;
private final int income;
public Person(String name, int age, int income) {
this.name = name;
this.age = age;
this.income = income;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int getIncome() {
return income;
}
#Override
public String toString() {
return "Person{" + "name=" + name + ", age=" + age + ", income=" + income + '}';
}
#Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + Objects.hashCode(this.name);
hash = 59 * hash + this.age;
hash = 59 * hash + this.income;
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if (this.age != other.age) {
return false;
}
if (this.income != other.income) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
return true;
}
}
This should do the trick
List<person> persons = Arrays.asList(
new person(22, 1000),
new person(25, 1500),
new person(22, 2500),
new person(32, 5000)
);
Map<Integer, Map<Integer, List<person>>> map = persons.stream().collect(
groupingBy(person::getAge, groupingBy(person::getIncome))
);
System.out.println(map);
Output:
{32={5000=[person{age=32, income=5000}]}, 22={2500=[person{age=22, income=2500}], 1000=[person{age=22, income=1000}]}, 25={1500=[person{age=25, income=1500}]}}
NB: The result is not exactly what you expect as you will get a Map<Integer, Map<Integer, List<person>>> instead of Map<Integer, Map<Integer, person>> but I assume that your initial question is not correct because if you have two persons with the same age and income, you will have only one person in your map instead of two
You should take a look at Collectors.groupingBy():
List<Person> persons = new ArrayList<>();
Map<Integer, Map<Integer, List<Person>>> map = persons.stream().collect(Collectors.groupingBy(person -> person.getAge(),Collectors.groupingBy(person -> person.getIncome())));
This should do your thing.
Why not (I assume your type is person, not persons, you used both)
for (person p : persons)
{
if (!results.containsKey(p.getAge())
results.put(p.getAge(), new HashMap<income,persons>());
results.get(p.getAge()).put(p.getIncome(), p);
}
You can also implement your own collector for achieving this. With the help of Guava you can do it in one line:
Map<Integer, Map<Integer, Person>> result = persons.stream().collect(HashMap::new, (store, person) -> store.put(person.getAge(), ImmutableMap.of(person.getIncome(), person)), HashMap::putAll);
I second YaRiK; a Guava Table<Integer, Integer, Set<Person>> would work nicely here. You should use a Set<Person> to avoid collisions, like user902383 suggests. The streams API isn't always the right tool, and this looks to me like a case where a traditional iterative loop will be much easier to read.
Try this:
Table<Integer, Integer, Set<Person>> table = HashBasedTable.create();
for (Person p : persons) {
Set<Person> s = table.get(p.getAge(), p.getIncome());
if (s == null) {
s = new HashSet<>();
table.put(p.getAge(), p.getIncome(), s);
}
s.add(p);
}

Sorting by values in HashMap class using Java

I'm trying to get results HashMap sorted by value.
This is HashMap's keys and values:
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
I try to get results like this:
1 = can
2 = selin
4 = burak
5 = ertu
Here is my code:
import java.util.*;
public class mapTers {
public static void main(String[] args) {
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
Integer dizi[] = new Integer[map.size()];
Set anahtarlar = map.keySet();
Iterator t = anahtarlar.iterator();
int a = 0;
while (t.hasNext()) {
dizi[a] = map.get(t.next());
a++;
}
Arrays.sort(dizi);
for (int i = 0; i < map.size(); i++) {
while (t.hasNext()) {
if (dizi[i].equals(map.get(t.next()))) {
System.out.println(dizi[i] + " = " + t.next());
}
}
}
}
}
You can sort the entries as follows (but note this won't sort the map itself, and also HashMap cannot be sorted) -
List<Map.Entry<String, Integer>> entryList = new ArrayList<Map.Entry<String, Integer>>(map.entrySet());
Collections.sort(entryList, new Comparator<Map.Entry<String, Integer>>() {
#Override
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
Every time that you call t.next(), the iterator's pointer is moved forward. Eventually, the iterator reaches the end. You need to reset the iterator. Also, calling t.next() twice moves the pointer twice.
Here's my solution:
import java.util.*;
public class mapTers
{
public static void main(String[] args)
{
HashMap<String, Integer> map = new HashMap<String, Integer>();
map.put("ertu", 5);
map.put("burak", 4);
map.put("selin", 2);
map.put("can", 1);
Integer dizi[] = new Integer[map.size()];
Set anahtarlar = map.keySet();
Iterator t = anahtarlar.iterator();
int a = 0;
while (t.hasNext())
{
dizi[a] = map.get(t.next());
a++;
}
Arrays.sort(dizi);
for (int i = 0; i < map.size(); i++)
{
t = anahtarlar.iterator();
while (t.hasNext())
{
String temp = (String)t.next();
if (dizi[i].equals(map.get(temp)))
{
System.out.println(dizi[i] + " = " + temp);
}
}
}
}
}
You cannot do that from a Map. At least not directly.
Retrieve the keys/entries, get all the map data in a more suitable structure (hint: a class that encapsulates both attributes and is is stored in a sortable (hint2: SortedSet, List)) and sort.
Do not forget to extend Comparable (and implement compareTo) or, otherwise, create a Comparator.
This is one of the solutions take from: https://stackoverflow.com/a/13913206/1256583
Just pass in the unsorted map, and you'll get the sorted one.
private static Map<String, Integer> sortByComparator(Map<String, Integer> unsortMap, final boolean order) {
List<Entry<String, Integer>> list = new LinkedList<Entry<String, Integer>>(unsortMap.entrySet());
// Sorting the list based on values
Collections.sort(list, new Comparator<Entry<String, Integer>>() {
public int compare(Entry<String, Integer> o1, Entry<String, Integer> o2) {
if (order) {
return o1.getValue().compareTo(o2.getValue());
}
else {
return o2.getValue().compareTo(o1.getValue());
}
}
});
// Maintaining insertion order with the help of LinkedList
Map<String, Integer> sortedMap = new LinkedHashMap<String, Integer>();
for (Entry<String, Integer> entry : list) {
sortedMap.put(entry.getKey(), entry.getValue());
}
return sortedMap;
}
To print, do a simple iteration over the entry set:
public static void printMap(Map<String, Integer> map) {
for (Entry<String, Integer> entry : map.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : "+ entry.getValue());
}
}
You probably have the wrong data structure for this problem. Either:
Reverse the map so the integers are the keys and the words the values and make the map a SortedMap, or
Use a bidirectional map as provided by libraries like Google Guava.
Reversed Map
private final SortedMap<Integer, String> TRANSLATIONS;
static {
SortedMap<Integer, String> map = new TreeMap<>();
map.put(1, "can");
// ...
TRANSLATIONS = Collections.unmodifiableSortedMap(map);
}
Guava BiMap
private final BiMap TRANSLATIONS =
new ImmutableBiMap.Builder<String, Integer>()
.put("ertu", 5);
.put("burak", 4);
.put("selin", 2);
.put("can", 1);
.build();
Then, iterate over a sorted version of the key set or value set as needed. For example,
TRANSLATIONS.inverse.get(4); // "burak"
I'm just curious. What language are your strings in?

Categories

Resources