Group by multiple field names in java 8Group by in Java 8 on multiple fields with aggregationsApache Commons Collections MultiValuedMap to filter data by multiple fieldsNeed to do a Map<K,Map<V,List<Y>>>Java 8 Nested (Multi level) group byAggregate List of objects in JavaGroup by two fields then summing BigDecimalJava 8 One Stream To Multiple MapJava Streams: Grouping a List by two fieldsGroup list elements in list of list in javaHow to use Java streams for the filteringIs Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?Does a finally block always get executed in Java?What is the difference between public, protected, package-private and private in Java?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?Why does Java have transient fields?How do I convert a String to an int in Java?Creating a memory leak with Java

Does the United States guarantee any unique freedoms?

Did WWII Japanese soldiers engage in cannibalism of their enemies?

Dereferencing a pointer in a for loop initializer creates a seg fault

Best gun to modify into a monsterhunter weapon?

How to remove something from the slug/url

Looking for a new job because of relocation - is it okay to tell the real reason?

Working examples for SemidefiniteOptimization

Physics of Guitar frets and sound

How do I calculate the difference in lens reach between a superzoom compact and a DSLR zoom lens?

CLR Stored Procedure on Azure SQL Managed Instance error on execution: "Assembly in host store has a different signature than assembly in GAC"

Is this cheap "air conditioner" able to cool a room?

As a 16 year old, how can I keep my money safe from my mother?

Shabbat clothing on shabbat chazon

Does this Foo machine halt?

sed delete all the words before a match

Pretty heat maps

Why does this Pokémon I just hatched need to be healed?

How do we avoid CI-driven development...?

Word or idiom defining something barely functional

A question about 'reptile and volatiles' to describe creatures

Geometric programming: Why are the constraints defined to be less than/equal to 1?

What happen if I gain the control of aura that enchants an opponent's creature? Would the aura stay attached?

Is TA-ing worth the opportunity cost?

Where to pee in London?



Group by multiple field names in java 8


Group by in Java 8 on multiple fields with aggregationsApache Commons Collections MultiValuedMap to filter data by multiple fieldsNeed to do a Map<K,Map<V,List<Y>>>Java 8 Nested (Multi level) group byAggregate List of objects in JavaGroup by two fields then summing BigDecimalJava 8 One Stream To Multiple MapJava Streams: Grouping a List by two fieldsGroup list elements in list of list in javaHow to use Java streams for the filteringIs Java “pass-by-reference” or “pass-by-value”?How do I efficiently iterate over each entry in a Java Map?Does a finally block always get executed in Java?What is the difference between public, protected, package-private and private in Java?How do I read / convert an InputStream into a String in Java?When to use LinkedList over ArrayList in Java?How do I generate random integers within a specific range in Java?Why does Java have transient fields?How do I convert a String to an int in Java?Creating a memory leak with Java






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








60















I found the code for grouping the objects by some field name from POJO. Below is the code for that:



public class Temp 

static class Person

private String name;
private int age;
private long salary;

Person(String name, int age, long salary)

this.name = name;
this.age = age;
this.salary = salary;


@Override
public String toString()
return String.format("Personname='%s', age=%d, salary=%d", name, age, salary);



public static void main(String[] args)
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);




And the output is (which is correct):



24=[Personname='Paul', age=24, salary=20000], 28=[Personname='Will', age=28, salary=28000, Personname='William', age=28, salary=28000], 30=[Personname='Mark', age=30, salary=30000]


But what if I want to group by multiple fields? I can obviously pass some POJO in groupingBy() method after implementing equals() method in that POJO but is there any other option like I can group by more than one fields from the given POJO?



E.g. here in my case, I want to group by name and age.










share|improve this question



















  • 1





    A trick is to just generate a unique string from all the fields.

    – Marko Topolnik
    Feb 5 '15 at 11:32






  • 3





    BTW mapping as a downstream collector is redundant in the code you have posted.

    – Marko Topolnik
    Feb 5 '15 at 11:41






  • 7





    Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

    – Misha
    Feb 5 '15 at 20:09

















60















I found the code for grouping the objects by some field name from POJO. Below is the code for that:



public class Temp 

static class Person

private String name;
private int age;
private long salary;

Person(String name, int age, long salary)

this.name = name;
this.age = age;
this.salary = salary;


@Override
public String toString()
return String.format("Personname='%s', age=%d, salary=%d", name, age, salary);



public static void main(String[] args)
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);




And the output is (which is correct):



24=[Personname='Paul', age=24, salary=20000], 28=[Personname='Will', age=28, salary=28000, Personname='William', age=28, salary=28000], 30=[Personname='Mark', age=30, salary=30000]


But what if I want to group by multiple fields? I can obviously pass some POJO in groupingBy() method after implementing equals() method in that POJO but is there any other option like I can group by more than one fields from the given POJO?



E.g. here in my case, I want to group by name and age.










share|improve this question



















  • 1





    A trick is to just generate a unique string from all the fields.

    – Marko Topolnik
    Feb 5 '15 at 11:32






  • 3





    BTW mapping as a downstream collector is redundant in the code you have posted.

    – Marko Topolnik
    Feb 5 '15 at 11:41






  • 7





    Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

    – Misha
    Feb 5 '15 at 20:09













60












60








60


21






I found the code for grouping the objects by some field name from POJO. Below is the code for that:



public class Temp 

static class Person

private String name;
private int age;
private long salary;

Person(String name, int age, long salary)

this.name = name;
this.age = age;
this.salary = salary;


@Override
public String toString()
return String.format("Personname='%s', age=%d, salary=%d", name, age, salary);



public static void main(String[] args)
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);




And the output is (which is correct):



24=[Personname='Paul', age=24, salary=20000], 28=[Personname='Will', age=28, salary=28000, Personname='William', age=28, salary=28000], 30=[Personname='Mark', age=30, salary=30000]


But what if I want to group by multiple fields? I can obviously pass some POJO in groupingBy() method after implementing equals() method in that POJO but is there any other option like I can group by more than one fields from the given POJO?



E.g. here in my case, I want to group by name and age.










share|improve this question














I found the code for grouping the objects by some field name from POJO. Below is the code for that:



public class Temp 

static class Person

private String name;
private int age;
private long salary;

Person(String name, int age, long salary)

this.name = name;
this.age = age;
this.salary = salary;


@Override
public String toString()
return String.format("Personname='%s', age=%d, salary=%d", name, age, salary);



public static void main(String[] args)
Stream<Person> people = Stream.of(new Person("Paul", 24, 20000),
new Person("Mark", 30, 30000),
new Person("Will", 28, 28000),
new Person("William", 28, 28000));
Map<Integer, List<Person>> peopleByAge;
peopleByAge = people
.collect(Collectors.groupingBy(p -> p.age, Collectors.mapping((Person p) -> p, toList())));
System.out.println(peopleByAge);




And the output is (which is correct):



24=[Personname='Paul', age=24, salary=20000], 28=[Personname='Will', age=28, salary=28000, Personname='William', age=28, salary=28000], 30=[Personname='Mark', age=30, salary=30000]


But what if I want to group by multiple fields? I can obviously pass some POJO in groupingBy() method after implementing equals() method in that POJO but is there any other option like I can group by more than one fields from the given POJO?



E.g. here in my case, I want to group by name and age.







java java-8






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 5 '15 at 11:30









Mital PritmaniMital Pritmani

2,0997 gold badges28 silver badges35 bronze badges




2,0997 gold badges28 silver badges35 bronze badges










  • 1





    A trick is to just generate a unique string from all the fields.

    – Marko Topolnik
    Feb 5 '15 at 11:32






  • 3





    BTW mapping as a downstream collector is redundant in the code you have posted.

    – Marko Topolnik
    Feb 5 '15 at 11:41






  • 7





    Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

    – Misha
    Feb 5 '15 at 20:09












  • 1





    A trick is to just generate a unique string from all the fields.

    – Marko Topolnik
    Feb 5 '15 at 11:32






  • 3





    BTW mapping as a downstream collector is redundant in the code you have posted.

    – Marko Topolnik
    Feb 5 '15 at 11:41






  • 7





    Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

    – Misha
    Feb 5 '15 at 20:09







1




1





A trick is to just generate a unique string from all the fields.

– Marko Topolnik
Feb 5 '15 at 11:32





A trick is to just generate a unique string from all the fields.

– Marko Topolnik
Feb 5 '15 at 11:32




3




3





BTW mapping as a downstream collector is redundant in the code you have posted.

– Marko Topolnik
Feb 5 '15 at 11:41





BTW mapping as a downstream collector is redundant in the code you have posted.

– Marko Topolnik
Feb 5 '15 at 11:41




7




7





Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

– Misha
Feb 5 '15 at 20:09





Quick and dirty solution is people.collect(groupingBy(p -> Arrays.asList(p.name, p.age))).

– Misha
Feb 5 '15 at 20:09












6 Answers
6






active

oldest

votes


















121














You have a few options here. The simplest is to chain your collectors:



Map<String, Map<Integer, List<Person>>> map = people
.collect(Collectors.groupingBy(Person::getName,
Collectors.groupingBy(Person::getAge));


Then to get a list of 18 year old people called Fred you would use:



map.get("Fred").get(18);


A second option is to define a class that represents the grouping. This can be inside Person:



class Person 
public static class NameAge
public NameAge(String name, int age)
...


// must implement equals and hash function


public NameAge getNameAge()
return new NameAge(name, age);




Then you can use:



Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));


and search with



map.get(new NameAge("Fred", 18));


Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:



Map<Pair<String, Integer>, List<Person>> map =
people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));


and retrieve with:



map.get(Pair.of("Fred", 18));


Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.



Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.



Good luck.






share|improve this answer






















  • 4





    Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

    – Marko Topolnik
    Feb 6 '15 at 13:53






  • 1





    Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

    – sprinter
    Feb 6 '15 at 13:59







  • 1





    Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

    – Marko Topolnik
    Feb 6 '15 at 14:02






  • 1





    Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

    – sprinter
    Feb 6 '15 at 14:04











  • seems so easy when you know the solution. Thanks!

    – IcedDante
    Oct 29 '15 at 21:14


















29














Here look at the code:



You can simply create a Function and let it do the work for you, kind of functional Style!



Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());


Now you can use it as a map:



Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


Cheers!






share|improve this answer






















  • 1





    I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

    – bpedroso
    Mar 17 at 5:54



















4














Hi You can simply concatenate your groupingByKey such as



Map<String, List<Person>> peopleBySomeKey = people
.collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



//write getGroupingByKey() function
private String getGroupingByKey(Person p)
return p.getAge()+"-"+p.getName();






share|improve this answer


































    4














    The groupingBy method has the first parameter is Function<T,K> where:




    @param <T> the type of the input elements



    @param <K> the type of the keys




    If we replace lambda with the anonymous class in your code, we can see some kind of that:



    people.stream().collect(Collectors.groupingBy(new Function<Person, int>() 
    @Override
    public int apply(Person person)
    return person.getAge();

    ));


    Just now change output parameter<K>. In this case, for example, I used a pair class from org.apache.commons.lang3.tuple for grouping by name and age, but you may create your own class for filtering groups as you need.



    people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() 
    @Override
    public YourFilter apply(Person person)
    return Pair.of(person.getAge(), person.getName());

    ));


    Finally, after replacing with lambda back, code looks like that:



    Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));





    share|improve this answer

























    • What about using List<String>?

      – Alex78191
      Nov 22 '18 at 16:45


















    1














    Define a class for key definition in your group.



    class KeyObj 

    ArrayList<Object> keys;

    public KeyObj( Object... objs )
    keys = new ArrayList<Object>();

    for (int i = 0; i < objs.length; i++)
    keys.add( objs[i] );



    // Add appropriate isEqual() ... you IDE should generate this




    Now in your code,



    peopleByManyParams = people
    .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));





    share|improve this answer




















    • 3





      That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

      – Marko Topolnik
      Feb 5 '15 at 11:57












    • And also similar to the Pair example mentioned in the other example, but without argument limit.

      – Benny Bottema
      Jul 9 '16 at 12:21











    • Also you need to make this immutable. (and calculate the hashCode ) once)

      – RobAu
      May 30 '17 at 9:58


















    0














    I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !



    Just to notice, I didn't use sorting, in order not to over complicate this example.



    This is my code :



    @Test
    public void test_2() throws Exception
    Firm catering = DS.firm().get(1);
    LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
    LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
    Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
    Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

    List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
    Map<Object, Long> M = LON.stream().collect(
    Collectors.groupingBy(p
    -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
    Collectors.counting()));

    for (Map.Entry<Object, Long> e : M.entrySet())
    Object key = e.getKey();
    Long value = e.getValue();
    System.err.println(String.format("Client firm :%s, total: %d", key, value));







    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%2f28342814%2fgroup-by-multiple-field-names-in-java-8%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      6 Answers
      6






      active

      oldest

      votes








      6 Answers
      6






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      121














      You have a few options here. The simplest is to chain your collectors:



      Map<String, Map<Integer, List<Person>>> map = people
      .collect(Collectors.groupingBy(Person::getName,
      Collectors.groupingBy(Person::getAge));


      Then to get a list of 18 year old people called Fred you would use:



      map.get("Fred").get(18);


      A second option is to define a class that represents the grouping. This can be inside Person:



      class Person 
      public static class NameAge
      public NameAge(String name, int age)
      ...


      // must implement equals and hash function


      public NameAge getNameAge()
      return new NameAge(name, age);




      Then you can use:



      Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));


      and search with



      map.get(new NameAge("Fred", 18));


      Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:



      Map<Pair<String, Integer>, List<Person>> map =
      people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));


      and retrieve with:



      map.get(Pair.of("Fred", 18));


      Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.



      Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.



      Good luck.






      share|improve this answer






















      • 4





        Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

        – Marko Topolnik
        Feb 6 '15 at 13:53






      • 1





        Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

        – sprinter
        Feb 6 '15 at 13:59







      • 1





        Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

        – Marko Topolnik
        Feb 6 '15 at 14:02






      • 1





        Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

        – sprinter
        Feb 6 '15 at 14:04











      • seems so easy when you know the solution. Thanks!

        – IcedDante
        Oct 29 '15 at 21:14















      121














      You have a few options here. The simplest is to chain your collectors:



      Map<String, Map<Integer, List<Person>>> map = people
      .collect(Collectors.groupingBy(Person::getName,
      Collectors.groupingBy(Person::getAge));


      Then to get a list of 18 year old people called Fred you would use:



      map.get("Fred").get(18);


      A second option is to define a class that represents the grouping. This can be inside Person:



      class Person 
      public static class NameAge
      public NameAge(String name, int age)
      ...


      // must implement equals and hash function


      public NameAge getNameAge()
      return new NameAge(name, age);




      Then you can use:



      Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));


      and search with



      map.get(new NameAge("Fred", 18));


      Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:



      Map<Pair<String, Integer>, List<Person>> map =
      people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));


      and retrieve with:



      map.get(Pair.of("Fred", 18));


      Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.



      Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.



      Good luck.






      share|improve this answer






















      • 4





        Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

        – Marko Topolnik
        Feb 6 '15 at 13:53






      • 1





        Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

        – sprinter
        Feb 6 '15 at 13:59







      • 1





        Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

        – Marko Topolnik
        Feb 6 '15 at 14:02






      • 1





        Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

        – sprinter
        Feb 6 '15 at 14:04











      • seems so easy when you know the solution. Thanks!

        – IcedDante
        Oct 29 '15 at 21:14













      121












      121








      121







      You have a few options here. The simplest is to chain your collectors:



      Map<String, Map<Integer, List<Person>>> map = people
      .collect(Collectors.groupingBy(Person::getName,
      Collectors.groupingBy(Person::getAge));


      Then to get a list of 18 year old people called Fred you would use:



      map.get("Fred").get(18);


      A second option is to define a class that represents the grouping. This can be inside Person:



      class Person 
      public static class NameAge
      public NameAge(String name, int age)
      ...


      // must implement equals and hash function


      public NameAge getNameAge()
      return new NameAge(name, age);




      Then you can use:



      Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));


      and search with



      map.get(new NameAge("Fred", 18));


      Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:



      Map<Pair<String, Integer>, List<Person>> map =
      people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));


      and retrieve with:



      map.get(Pair.of("Fred", 18));


      Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.



      Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.



      Good luck.






      share|improve this answer















      You have a few options here. The simplest is to chain your collectors:



      Map<String, Map<Integer, List<Person>>> map = people
      .collect(Collectors.groupingBy(Person::getName,
      Collectors.groupingBy(Person::getAge));


      Then to get a list of 18 year old people called Fred you would use:



      map.get("Fred").get(18);


      A second option is to define a class that represents the grouping. This can be inside Person:



      class Person 
      public static class NameAge
      public NameAge(String name, int age)
      ...


      // must implement equals and hash function


      public NameAge getNameAge()
      return new NameAge(name, age);




      Then you can use:



      Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));


      and search with



      map.get(new NameAge("Fred", 18));


      Finally if you don't want to implement your own group class then many of the Java frameworks around have a pair class designed for exactly this type of thing. For example: apache commons pair If you use one of these libraries then you can make the key to the map a pair of the name and age:



      Map<Pair<String, Integer>, List<Person>> map =
      people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));


      and retrieve with:



      map.get(Pair.of("Fred", 18));


      Personally I really dislike these tuple libraries. They seem to be the exact opposite of good OO design: they hide intent instead of exposing it.



      Having said that you can combine the second two options by defining your own grouping class but implementing it by just extending Pair - that saves you a lot of the work involved in defining equals etc and hides the use of the tuple as just a convenient implementation detail like any other collection.



      Good luck.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Feb 9 '16 at 22:57

























      answered Feb 5 '15 at 12:35









      sprintersprinter

      17.7k4 gold badges32 silver badges61 bronze badges




      17.7k4 gold badges32 silver badges61 bronze badges










      • 4





        Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

        – Marko Topolnik
        Feb 6 '15 at 13:53






      • 1





        Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

        – sprinter
        Feb 6 '15 at 13:59







      • 1





        Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

        – Marko Topolnik
        Feb 6 '15 at 14:02






      • 1





        Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

        – sprinter
        Feb 6 '15 at 14:04











      • seems so easy when you know the solution. Thanks!

        – IcedDante
        Oct 29 '15 at 21:14












      • 4





        Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

        – Marko Topolnik
        Feb 6 '15 at 13:53






      • 1





        Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

        – sprinter
        Feb 6 '15 at 13:59







      • 1





        Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

        – Marko Topolnik
        Feb 6 '15 at 14:02






      • 1





        Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

        – sprinter
        Feb 6 '15 at 14:04











      • seems so easy when you know the solution. Thanks!

        – IcedDante
        Oct 29 '15 at 21:14







      4




      4





      Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

      – Marko Topolnik
      Feb 6 '15 at 13:53





      Function<T,U> also hides intent in this sense---but you won't see anyone declaring their own functional interface for each mapping step; the intent is already there in the lambda body. Same with tuples: they are great as glue types between API components. BTW Scala's case classes are IMHO a big win in terms of both conciseness and intent exposure.

      – Marko Topolnik
      Feb 6 '15 at 13:53




      1




      1





      Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

      – sprinter
      Feb 6 '15 at 13:59






      Yes I see your point. I guess (like always) it depends how they are used. The example I gave above - using a Pair as the key of a Map - is a good example of how not to do it. I'm not too familiar with Scala - will have to start learning it as I hear good things.

      – sprinter
      Feb 6 '15 at 13:59





      1




      1





      Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

      – Marko Topolnik
      Feb 6 '15 at 14:02





      Just imagine being able to declare NameAge as a one-liner: case class NameAge val name: String; val age: Int ---and you get equals, hashCode, and toString!

      – Marko Topolnik
      Feb 6 '15 at 14:02




      1




      1





      Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

      – sprinter
      Feb 6 '15 at 14:04





      Nice -- another item pushed onto my 'must do' queue. It's FIFO unfortunately!

      – sprinter
      Feb 6 '15 at 14:04













      seems so easy when you know the solution. Thanks!

      – IcedDante
      Oct 29 '15 at 21:14





      seems so easy when you know the solution. Thanks!

      – IcedDante
      Oct 29 '15 at 21:14













      29














      Here look at the code:



      You can simply create a Function and let it do the work for you, kind of functional Style!



      Function<Person, List<Object>> compositeKey = personRecord ->
      Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());


      Now you can use it as a map:



      Map<Object, List<Person>> map =
      people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


      Cheers!






      share|improve this answer






















      • 1





        I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

        – bpedroso
        Mar 17 at 5:54
















      29














      Here look at the code:



      You can simply create a Function and let it do the work for you, kind of functional Style!



      Function<Person, List<Object>> compositeKey = personRecord ->
      Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());


      Now you can use it as a map:



      Map<Object, List<Person>> map =
      people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


      Cheers!






      share|improve this answer






















      • 1





        I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

        – bpedroso
        Mar 17 at 5:54














      29












      29








      29







      Here look at the code:



      You can simply create a Function and let it do the work for you, kind of functional Style!



      Function<Person, List<Object>> compositeKey = personRecord ->
      Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());


      Now you can use it as a map:



      Map<Object, List<Person>> map =
      people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


      Cheers!






      share|improve this answer















      Here look at the code:



      You can simply create a Function and let it do the work for you, kind of functional Style!



      Function<Person, List<Object>> compositeKey = personRecord ->
      Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());


      Now you can use it as a map:



      Map<Object, List<Person>> map =
      people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));


      Cheers!







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Oct 23 '17 at 7:37









      Farhan S.

      5036 silver badges21 bronze badges




      5036 silver badges21 bronze badges










      answered Dec 22 '16 at 12:45









      Deepesh RehiDeepesh Rehi

      3743 silver badges19 bronze badges




      3743 silver badges19 bronze badges










      • 1





        I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

        – bpedroso
        Mar 17 at 5:54













      • 1





        I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

        – bpedroso
        Mar 17 at 5:54








      1




      1





      I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

      – bpedroso
      Mar 17 at 5:54






      I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());

      – bpedroso
      Mar 17 at 5:54












      4














      Hi You can simply concatenate your groupingByKey such as



      Map<String, List<Person>> peopleBySomeKey = people
      .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



      //write getGroupingByKey() function
      private String getGroupingByKey(Person p)
      return p.getAge()+"-"+p.getName();






      share|improve this answer































        4














        Hi You can simply concatenate your groupingByKey such as



        Map<String, List<Person>> peopleBySomeKey = people
        .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



        //write getGroupingByKey() function
        private String getGroupingByKey(Person p)
        return p.getAge()+"-"+p.getName();






        share|improve this answer





























          4












          4








          4







          Hi You can simply concatenate your groupingByKey such as



          Map<String, List<Person>> peopleBySomeKey = people
          .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



          //write getGroupingByKey() function
          private String getGroupingByKey(Person p)
          return p.getAge()+"-"+p.getName();






          share|improve this answer















          Hi You can simply concatenate your groupingByKey such as



          Map<String, List<Person>> peopleBySomeKey = people
          .collect(Collectors.groupingBy(p -> getGroupingByKey(p), Collectors.mapping((Person p) -> p, toList())));



          //write getGroupingByKey() function
          private String getGroupingByKey(Person p)
          return p.getAge()+"-"+p.getName();







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 2 '16 at 5:56









          Anptk

          1,0541 gold badge16 silver badges27 bronze badges




          1,0541 gold badge16 silver badges27 bronze badges










          answered Nov 2 '16 at 4:15









          AmandeepAmandeep

          413 bronze badges




          413 bronze badges
























              4














              The groupingBy method has the first parameter is Function<T,K> where:




              @param <T> the type of the input elements



              @param <K> the type of the keys




              If we replace lambda with the anonymous class in your code, we can see some kind of that:



              people.stream().collect(Collectors.groupingBy(new Function<Person, int>() 
              @Override
              public int apply(Person person)
              return person.getAge();

              ));


              Just now change output parameter<K>. In this case, for example, I used a pair class from org.apache.commons.lang3.tuple for grouping by name and age, but you may create your own class for filtering groups as you need.



              people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() 
              @Override
              public YourFilter apply(Person person)
              return Pair.of(person.getAge(), person.getName());

              ));


              Finally, after replacing with lambda back, code looks like that:



              Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer

























              • What about using List<String>?

                – Alex78191
                Nov 22 '18 at 16:45















              4














              The groupingBy method has the first parameter is Function<T,K> where:




              @param <T> the type of the input elements



              @param <K> the type of the keys




              If we replace lambda with the anonymous class in your code, we can see some kind of that:



              people.stream().collect(Collectors.groupingBy(new Function<Person, int>() 
              @Override
              public int apply(Person person)
              return person.getAge();

              ));


              Just now change output parameter<K>. In this case, for example, I used a pair class from org.apache.commons.lang3.tuple for grouping by name and age, but you may create your own class for filtering groups as you need.



              people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() 
              @Override
              public YourFilter apply(Person person)
              return Pair.of(person.getAge(), person.getName());

              ));


              Finally, after replacing with lambda back, code looks like that:



              Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer

























              • What about using List<String>?

                – Alex78191
                Nov 22 '18 at 16:45













              4












              4








              4







              The groupingBy method has the first parameter is Function<T,K> where:




              @param <T> the type of the input elements



              @param <K> the type of the keys




              If we replace lambda with the anonymous class in your code, we can see some kind of that:



              people.stream().collect(Collectors.groupingBy(new Function<Person, int>() 
              @Override
              public int apply(Person person)
              return person.getAge();

              ));


              Just now change output parameter<K>. In this case, for example, I used a pair class from org.apache.commons.lang3.tuple for grouping by name and age, but you may create your own class for filtering groups as you need.



              people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() 
              @Override
              public YourFilter apply(Person person)
              return Pair.of(person.getAge(), person.getName());

              ));


              Finally, after replacing with lambda back, code looks like that:



              Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer













              The groupingBy method has the first parameter is Function<T,K> where:




              @param <T> the type of the input elements



              @param <K> the type of the keys




              If we replace lambda with the anonymous class in your code, we can see some kind of that:



              people.stream().collect(Collectors.groupingBy(new Function<Person, int>() 
              @Override
              public int apply(Person person)
              return person.getAge();

              ));


              Just now change output parameter<K>. In this case, for example, I used a pair class from org.apache.commons.lang3.tuple for grouping by name and age, but you may create your own class for filtering groups as you need.



              people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() 
              @Override
              public YourFilter apply(Person person)
              return Pair.of(person.getAge(), person.getName());

              ));


              Finally, after replacing with lambda back, code looks like that:



              Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Jun 20 '18 at 13:35









              Andrei SmirnovAndrei Smirnov

              411 bronze badge




              411 bronze badge















              • What about using List<String>?

                – Alex78191
                Nov 22 '18 at 16:45

















              • What about using List<String>?

                – Alex78191
                Nov 22 '18 at 16:45
















              What about using List<String>?

              – Alex78191
              Nov 22 '18 at 16:45





              What about using List<String>?

              – Alex78191
              Nov 22 '18 at 16:45











              1














              Define a class for key definition in your group.



              class KeyObj 

              ArrayList<Object> keys;

              public KeyObj( Object... objs )
              keys = new ArrayList<Object>();

              for (int i = 0; i < objs.length; i++)
              keys.add( objs[i] );



              // Add appropriate isEqual() ... you IDE should generate this




              Now in your code,



              peopleByManyParams = people
              .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer




















              • 3





                That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

                – Marko Topolnik
                Feb 5 '15 at 11:57












              • And also similar to the Pair example mentioned in the other example, but without argument limit.

                – Benny Bottema
                Jul 9 '16 at 12:21











              • Also you need to make this immutable. (and calculate the hashCode ) once)

                – RobAu
                May 30 '17 at 9:58















              1














              Define a class for key definition in your group.



              class KeyObj 

              ArrayList<Object> keys;

              public KeyObj( Object... objs )
              keys = new ArrayList<Object>();

              for (int i = 0; i < objs.length; i++)
              keys.add( objs[i] );



              // Add appropriate isEqual() ... you IDE should generate this




              Now in your code,



              peopleByManyParams = people
              .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer




















              • 3





                That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

                – Marko Topolnik
                Feb 5 '15 at 11:57












              • And also similar to the Pair example mentioned in the other example, but without argument limit.

                – Benny Bottema
                Jul 9 '16 at 12:21











              • Also you need to make this immutable. (and calculate the hashCode ) once)

                – RobAu
                May 30 '17 at 9:58













              1












              1








              1







              Define a class for key definition in your group.



              class KeyObj 

              ArrayList<Object> keys;

              public KeyObj( Object... objs )
              keys = new ArrayList<Object>();

              for (int i = 0; i < objs.length; i++)
              keys.add( objs[i] );



              // Add appropriate isEqual() ... you IDE should generate this




              Now in your code,



              peopleByManyParams = people
              .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));





              share|improve this answer













              Define a class for key definition in your group.



              class KeyObj 

              ArrayList<Object> keys;

              public KeyObj( Object... objs )
              keys = new ArrayList<Object>();

              for (int i = 0; i < objs.length; i++)
              keys.add( objs[i] );



              // Add appropriate isEqual() ... you IDE should generate this




              Now in your code,



              peopleByManyParams = people
              .collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));






              share|improve this answer












              share|improve this answer



              share|improve this answer










              answered Feb 5 '15 at 11:48









              Sarvesh Kumar SinghSarvesh Kumar Singh

              8,71819 silver badges37 bronze badges




              8,71819 silver badges37 bronze badges










              • 3





                That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

                – Marko Topolnik
                Feb 5 '15 at 11:57












              • And also similar to the Pair example mentioned in the other example, but without argument limit.

                – Benny Bottema
                Jul 9 '16 at 12:21











              • Also you need to make this immutable. (and calculate the hashCode ) once)

                – RobAu
                May 30 '17 at 9:58












              • 3





                That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

                – Marko Topolnik
                Feb 5 '15 at 11:57












              • And also similar to the Pair example mentioned in the other example, but without argument limit.

                – Benny Bottema
                Jul 9 '16 at 12:21











              • Also you need to make this immutable. (and calculate the hashCode ) once)

                – RobAu
                May 30 '17 at 9:58







              3




              3





              That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

              – Marko Topolnik
              Feb 5 '15 at 11:57






              That's just reinventing Ararys.asList()---which is BTW a fine choice for OP's case.

              – Marko Topolnik
              Feb 5 '15 at 11:57














              And also similar to the Pair example mentioned in the other example, but without argument limit.

              – Benny Bottema
              Jul 9 '16 at 12:21





              And also similar to the Pair example mentioned in the other example, but without argument limit.

              – Benny Bottema
              Jul 9 '16 at 12:21













              Also you need to make this immutable. (and calculate the hashCode ) once)

              – RobAu
              May 30 '17 at 9:58





              Also you need to make this immutable. (and calculate the hashCode ) once)

              – RobAu
              May 30 '17 at 9:58











              0














              I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !



              Just to notice, I didn't use sorting, in order not to over complicate this example.



              This is my code :



              @Test
              public void test_2() throws Exception
              Firm catering = DS.firm().get(1);
              LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
              LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
              Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
              Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

              List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
              Map<Object, Long> M = LON.stream().collect(
              Collectors.groupingBy(p
              -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
              Collectors.counting()));

              for (Map.Entry<Object, Long> e : M.entrySet())
              Object key = e.getKey();
              Long value = e.getValue();
              System.err.println(String.format("Client firm :%s, total: %d", key, value));







              share|improve this answer































                0














                I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !



                Just to notice, I didn't use sorting, in order not to over complicate this example.



                This is my code :



                @Test
                public void test_2() throws Exception
                Firm catering = DS.firm().get(1);
                LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
                LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
                Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
                Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

                List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
                Map<Object, Long> M = LON.stream().collect(
                Collectors.groupingBy(p
                -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                Collectors.counting()));

                for (Map.Entry<Object, Long> e : M.entrySet())
                Object key = e.getKey();
                Long value = e.getValue();
                System.err.println(String.format("Client firm :%s, total: %d", key, value));







                share|improve this answer





























                  0












                  0








                  0







                  I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !



                  Just to notice, I didn't use sorting, in order not to over complicate this example.



                  This is my code :



                  @Test
                  public void test_2() throws Exception
                  Firm catering = DS.firm().get(1);
                  LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
                  LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
                  Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
                  Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

                  List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
                  Map<Object, Long> M = LON.stream().collect(
                  Collectors.groupingBy(p
                  -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                  Collectors.counting()));

                  for (Map.Entry<Object, Long> e : M.entrySet())
                  Object key = e.getKey();
                  Long value = e.getValue();
                  System.err.println(String.format("Client firm :%s, total: %d", key, value));







                  share|improve this answer















                  I needed to make report for a catering firm which serves lunches for various clients. In other words, catering may have on or more firms which take orders from catering, and it must know how many lunches it must produce every single day for all it's clients !



                  Just to notice, I didn't use sorting, in order not to over complicate this example.



                  This is my code :



                  @Test
                  public void test_2() throws Exception
                  Firm catering = DS.firm().get(1);
                  LocalDateTime ldtFrom = LocalDateTime.of(2017, Month.JANUARY, 1, 0, 0);
                  LocalDateTime ldtTo = LocalDateTime.of(2017, Month.MAY, 2, 0, 0);
                  Date dFrom = Date.from(ldtFrom.atZone(ZoneId.systemDefault()).toInstant());
                  Date dTo = Date.from(ldtTo.atZone(ZoneId.systemDefault()).toInstant());

                  List<PersonOrders> LON = DS.firm().getAllOrders(catering, dFrom, dTo, false);
                  Map<Object, Long> M = LON.stream().collect(
                  Collectors.groupingBy(p
                  -> Arrays.asList(p.getDatum(), p.getPerson().getIdfirm(), p.getIdProduct()),
                  Collectors.counting()));

                  for (Map.Entry<Object, Long> e : M.entrySet())
                  Object key = e.getKey();
                  Long value = e.getValue();
                  System.err.println(String.format("Client firm :%s, total: %d", key, value));








                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited May 2 '17 at 7:20

























                  answered May 2 '17 at 6:11









                  dobrivojedobrivoje

                  1121 silver badge8 bronze badges




                  1121 silver badge8 bronze badges






























                      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.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f28342814%2fgroup-by-multiple-field-names-in-java-8%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

                      Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

                      Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

                      Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript