# Grouping and Double sorting List

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))
{
} else
{
List<Person> p = new ArrayList<>();
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;
}
}
```

```Map<Integer, List<Person>> grouped = new HashMap<>();
people.forEach(person -> grouped.computeIfAbsent(
person.getAge(),
k -> new ArrayList<>())
```

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.