我找到了通过POJO中的某个字段名称对对象进行分组的代码.以下是代码:
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("Person{name='%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);
}
}
Run Code Online (Sandbox Code Playgroud)
输出是(这是正确的):
{24=[Person{name='Paul', age=24, salary=20000}], 28=[Person{name='Will', age=28, salary=28000}, Person{name='William', age=28, salary=28000}], 30=[Person{name='Mark', age=30, salary=30000}]}
Run Code Online (Sandbox Code Playgroud)
但是,如果我想按多个字段分组呢?显然,在POJO中groupingBy()
实现equals()
方法之后,我可以在方法中传递一些POJO,但是还有其他选项,比如我可以通过给定POJO中的多个字段进行分组吗?
例如,在我的情况下,我想按名称和年龄分组.
spr*_*ter 128
你有几个选择.最简单的是链接你的收藏家:
Map<String, Map<Integer, List<Person>>> map = people
.collect(Collectors.groupingBy(Person::getName,
Collectors.groupingBy(Person::getAge));
Run Code Online (Sandbox Code Playgroud)
然后,要获得一份名为弗雷德的18岁年轻人名单,您将使用:
map.get("Fred").get(18);
Run Code Online (Sandbox Code Playgroud)
第二种选择是定义表示分组的类.这可以在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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以使用:
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
Run Code Online (Sandbox Code Playgroud)
和搜索
map.get(new NameAge("Fred", 18));
Run Code Online (Sandbox Code Playgroud)
最后,如果您不想实现自己的组类,那么许多Java框架都有一个pair
专门为这类事物设计的类.例如:apache commons pair如果您使用其中一个库,那么您可以为地图创建一对名称和年龄:
Map<Pair<String, Integer>, List<Person>> map =
people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));
Run Code Online (Sandbox Code Playgroud)
并检索:
map.get(Pair.of("Fred", 18));
Run Code Online (Sandbox Code Playgroud)
就个人而言,我真的不喜欢这些元组库.它们似乎与优秀的OO设计完全相反:它们隐藏意图而不是暴露它.
虽然已经说过你可以通过定义自己的分组类来组合后两个选项,但只是通过扩展来实现它Pair
- 这为你节省了很多定义的工作,equals
并隐藏了元组的使用,就像任何一个方便的实现细节一样其他收藏品.
祝好运.
Dee*_*ehi 35
在这里看代码:
您可以简单地创建一个功能,让它为您完成工作,一种功能性的风格!
Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
Run Code Online (Sandbox Code Playgroud)
现在您可以将它用作地图:
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
Run Code Online (Sandbox Code Playgroud)
干杯!
小智 8
嗨,您可以简单地连接您的groupingByKey
诸如
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();
}
Run Code Online (Sandbox Code Playgroud)
小智 7
该groupingBy
方法具有的第一个参数是Function<T,K>
:
@param
<T>
输入元素的类型@param
<K>
键的类型
如果在您的代码中将lambda替换为匿名类,则可以看到以下内容:
people.stream().collect(Collectors.groupingBy(new Function<Person, int>() {
@Override
public int apply(Person person) {
return person.getAge();
}
}));
Run Code Online (Sandbox Code Playgroud)
刚才更改输出参数<K>
。例如,在这种情况下,我使用了org.apache.commons.lang3.tuple中的pair类按名称和年龄进行分组,但是您可以根据需要创建自己的类以过滤组。
people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {
@Override
public YourFilter apply(Person person) {
return Pair.of(person.getAge(), person.getName());
}
}));
Run Code Online (Sandbox Code Playgroud)
最后,用lambda back替换后,代码如下所示:
Map<Pair<Integer,String>, List<Person>> peopleByAgeAndName = people.collect(Collectors.groupingBy(p -> Pair.of(person.getAge(), person.getName()), Collectors.mapping((Person p) -> p, toList())));
Run Code Online (Sandbox Code Playgroud)
您可以使用 List 作为许多字段的分类器,但您需要将空值包装到 Optional 中:
Function<Item, List> classifier = (item) -> List.of(
item.getFieldA(),
item.getFieldB(),
Optional.ofNullable(item.getFieldC())
);
Map<List, List<Item>> grouped = items.stream()
.collect(Collectors.groupingBy(classifier));
Run Code Online (Sandbox Code Playgroud)
为您的组中的关键定义定义一个类。
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
}
Run Code Online (Sandbox Code Playgroud)
现在在你的代码中,
peopleByManyParams = people
.collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
92531 次 |
最近记录: |