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;
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
add a comment |
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
1
A trick is to just generate a unique string from all the fields.
– Marko Topolnik
Feb 5 '15 at 11:32
3
BTWmapping
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 ispeople.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
.
– Misha
Feb 5 '15 at 20:09
add a comment |
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
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
java java-8
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
BTWmapping
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 ispeople.collect(groupingBy(p -> Arrays.asList(p.name, p.age)))
.
– Misha
Feb 5 '15 at 20:09
add a comment |
1
A trick is to just generate a unique string from all the fields.
– Marko Topolnik
Feb 5 '15 at 11:32
3
BTWmapping
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 ispeople.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
add a comment |
6 Answers
6
active
oldest
votes
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.
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 declareNameAge
as a one-liner:case class NameAge val name: String; val age: Int
---and you getequals
,hashCode
, andtoString
!
– 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
|
show 4 more comments
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!
1
I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());
– bpedroso
Mar 17 at 5:54
add a comment |
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();
add a comment |
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())));
What about usingList<String>
?
– Alex78191
Nov 22 '18 at 16:45
add a comment |
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())));
3
That's just reinventingArarys.asList()
---which is BTW a fine choice for OP's case.
– Marko Topolnik
Feb 5 '15 at 11:57
And also similar to thePair
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 thehashCode
) once)
– RobAu
May 30 '17 at 9:58
add a comment |
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));
add a comment |
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
);
);
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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 declareNameAge
as a one-liner:case class NameAge val name: String; val age: Int
---and you getequals
,hashCode
, andtoString
!
– 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
|
show 4 more comments
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.
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 declareNameAge
as a one-liner:case class NameAge val name: String; val age: Int
---and you getequals
,hashCode
, andtoString
!
– 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
|
show 4 more comments
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.
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.
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 declareNameAge
as a one-liner:case class NameAge val name: String; val age: Int
---and you getequals
,hashCode
, andtoString
!
– 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
|
show 4 more comments
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 declareNameAge
as a one-liner:case class NameAge val name: String; val age: Int
---and you getequals
,hashCode
, andtoString
!
– 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
|
show 4 more comments
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!
1
I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());
– bpedroso
Mar 17 at 5:54
add a comment |
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!
1
I used this solution but different. Function<Person, String> compositeKey = personRecord -> StringUtils.join(personRecord.getName(), personRecord.getAge());
– bpedroso
Mar 17 at 5:54
add a comment |
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!
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!
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
add a comment |
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
add a comment |
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();
add a comment |
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();
add a comment |
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();
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();
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
add a comment |
add a comment |
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())));
What about usingList<String>
?
– Alex78191
Nov 22 '18 at 16:45
add a comment |
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())));
What about usingList<String>
?
– Alex78191
Nov 22 '18 at 16:45
add a comment |
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())));
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())));
answered Jun 20 '18 at 13:35
Andrei SmirnovAndrei Smirnov
411 bronze badge
411 bronze badge
What about usingList<String>
?
– Alex78191
Nov 22 '18 at 16:45
add a comment |
What about usingList<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
add a comment |
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())));
3
That's just reinventingArarys.asList()
---which is BTW a fine choice for OP's case.
– Marko Topolnik
Feb 5 '15 at 11:57
And also similar to thePair
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 thehashCode
) once)
– RobAu
May 30 '17 at 9:58
add a comment |
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())));
3
That's just reinventingArarys.asList()
---which is BTW a fine choice for OP's case.
– Marko Topolnik
Feb 5 '15 at 11:57
And also similar to thePair
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 thehashCode
) once)
– RobAu
May 30 '17 at 9:58
add a comment |
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())));
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())));
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 reinventingArarys.asList()
---which is BTW a fine choice for OP's case.
– Marko Topolnik
Feb 5 '15 at 11:57
And also similar to thePair
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 thehashCode
) once)
– RobAu
May 30 '17 at 9:58
add a comment |
3
That's just reinventingArarys.asList()
---which is BTW a fine choice for OP's case.
– Marko Topolnik
Feb 5 '15 at 11:57
And also similar to thePair
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 thehashCode
) 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
add a comment |
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));
add a comment |
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));
add a comment |
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));
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));
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
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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