Grouping and Double sorting List












3














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;
}
}









share|improve this question





























    3














    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;
    }
    }









    share|improve this question



























      3












      3








      3







      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;
      }
      }









      share|improve this question















      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;
      }
      }






      java sorting






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 19 '18 at 19:12

























      asked Nov 19 '18 at 12:49









      CallMeBob

      2,64721530




      2,64721530
























          4 Answers
          4






          active

          oldest

          votes


















          1














          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.






          share|improve this answer























          • Nice and quick! Thanks :)
            – CallMeBob
            Nov 19 '18 at 16:43



















          2














          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).






          share|improve this answer























          • thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
            – CallMeBob
            Nov 19 '18 at 12:58










          • So add some more type information.
            – Andy Turner
            Nov 19 '18 at 12:59










          • Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
            – CallMeBob
            Nov 19 '18 at 13:09



















          1














          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;
          }





          share|improve this answer





























            0














            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






            share|improve this answer





















              Your Answer






              StackExchange.ifUsing("editor", function () {
              StackExchange.using("externalEditor", function () {
              StackExchange.using("snippets", function () {
              StackExchange.snippets.init();
              });
              });
              }, "code-snippets");

              StackExchange.ready(function() {
              var channelOptions = {
              tags: "".split(" "),
              id: "1"
              };
              initTagRenderer("".split(" "), "".split(" "), channelOptions);

              StackExchange.using("externalEditor", function() {
              // Have to fire editor after snippets, if snippets enabled
              if (StackExchange.settings.snippets.snippetsEnabled) {
              StackExchange.using("snippets", function() {
              createEditor();
              });
              }
              else {
              createEditor();
              }
              });

              function createEditor() {
              StackExchange.prepareEditor({
              heartbeatType: 'answer',
              autoActivateHeartbeat: false,
              convertImagesToLinks: true,
              noModals: true,
              showLowRepImageUploadWarning: true,
              reputationToPostImages: 10,
              bindNavPrevention: true,
              postfix: "",
              imageUploader: {
              brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
              contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
              allowUrls: true
              },
              onDemand: true,
              discardSelector: ".discard-answer"
              ,immediatelyShowMarkdownHelp:true
              });


              }
              });














              draft saved

              draft discarded


















              StackExchange.ready(
              function () {
              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53375009%2fgrouping-and-double-sorting-listperson%23new-answer', 'question_page');
              }
              );

              Post as a guest















              Required, but never shown

























              4 Answers
              4






              active

              oldest

              votes








              4 Answers
              4






              active

              oldest

              votes









              active

              oldest

              votes






              active

              oldest

              votes









              1














              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.






              share|improve this answer























              • Nice and quick! Thanks :)
                – CallMeBob
                Nov 19 '18 at 16:43
















              1














              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.






              share|improve this answer























              • Nice and quick! Thanks :)
                – CallMeBob
                Nov 19 '18 at 16:43














              1












              1








              1






              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.






              share|improve this answer














              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.







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 19 '18 at 15:58

























              answered Nov 19 '18 at 13:31









              Federico Peralta Schaffner

              21.9k43370




              21.9k43370












              • Nice and quick! Thanks :)
                – CallMeBob
                Nov 19 '18 at 16:43


















              • Nice and quick! Thanks :)
                – CallMeBob
                Nov 19 '18 at 16:43
















              Nice and quick! Thanks :)
              – CallMeBob
              Nov 19 '18 at 16:43




              Nice and quick! Thanks :)
              – CallMeBob
              Nov 19 '18 at 16:43













              2














              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).






              share|improve this answer























              • thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
                – CallMeBob
                Nov 19 '18 at 12:58










              • So add some more type information.
                – Andy Turner
                Nov 19 '18 at 12:59










              • Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
                – CallMeBob
                Nov 19 '18 at 13:09
















              2














              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).






              share|improve this answer























              • thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
                – CallMeBob
                Nov 19 '18 at 12:58










              • So add some more type information.
                – Andy Turner
                Nov 19 '18 at 12:59










              • Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
                – CallMeBob
                Nov 19 '18 at 13:09














              2












              2








              2






              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).






              share|improve this answer














              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).







              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Nov 19 '18 at 13:24

























              answered Nov 19 '18 at 12:53









              Andy Turner

              80.4k880134




              80.4k880134












              • thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
                – CallMeBob
                Nov 19 '18 at 12:58










              • So add some more type information.
                – Andy Turner
                Nov 19 '18 at 12:59










              • Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
                – CallMeBob
                Nov 19 '18 at 13:09


















              • thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
                – CallMeBob
                Nov 19 '18 at 12:58










              • So add some more type information.
                – Andy Turner
                Nov 19 '18 at 12:59










              • Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
                – CallMeBob
                Nov 19 '18 at 13:09
















              thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
              – CallMeBob
              Nov 19 '18 at 12:58




              thanks for quick reply. It doesn't seem to understand e.getValue() and e.getKey() though - 'Cannot resolve method'.
              – CallMeBob
              Nov 19 '18 at 12:58












              So add some more type information.
              – Andy Turner
              Nov 19 '18 at 12:59




              So add some more type information.
              – Andy Turner
              Nov 19 '18 at 12:59












              Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
              – CallMeBob
              Nov 19 '18 at 13:09




              Yes, seems to work the magic! Many thanks. I spend unseasonable amount of time on it before posting here. You cracked it in 5 minutes... :)
              – CallMeBob
              Nov 19 '18 at 13:09











              1














              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;
              }





              share|improve this answer


























                1














                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;
                }





                share|improve this answer
























                  1












                  1








                  1






                  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;
                  }





                  share|improve this answer












                  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;
                  }






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 19 '18 at 13:32









                  Slaw

                  6,6992931




                  6,6992931























                      0














                      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






                      share|improve this answer


























                        0














                        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






                        share|improve this answer
























                          0












                          0








                          0






                          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






                          share|improve this answer












                          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







                          share|improve this answer












                          share|improve this answer



                          share|improve this answer










                          answered Nov 19 '18 at 13:29









                          Renny

                          608




                          608






























                              draft saved

                              draft discarded




















































                              Thanks for contributing an answer to Stack Overflow!


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.





                              Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                              Please pay close attention to the following guidance:


                              • Please be sure to answer the question. Provide details and share your research!

                              But avoid



                              • Asking for help, clarification, or responding to other answers.

                              • Making statements based on opinion; back them up with references or personal experience.


                              To learn more, see our tips on writing great answers.




                              draft saved


                              draft discarded














                              StackExchange.ready(
                              function () {
                              StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53375009%2fgrouping-and-double-sorting-listperson%23new-answer', 'question_page');
                              }
                              );

                              Post as a guest















                              Required, but never shown





















































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown

































                              Required, but never shown














                              Required, but never shown












                              Required, but never shown







                              Required, but never shown







                              Popular posts from this blog

                              MongoDB - Not Authorized To Execute Command

                              in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith

                              How to fix TextFormField cause rebuild widget in Flutter