我找到了通过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);
}
}
输出是(这是正确的):
{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}]}
但是,如果我想按多个字段分组呢?显然,在POJO中实现groupingBy()
方法后,我可以在equals()
方法中传递一些POJO,但是还有其他选项,比如我可以通过给定POJO中的多个字段进行分组吗?
E.g。在我的情况下,我想按姓名和年龄分组。
答案 0 :(得分:109)
这里有几个选项。最简单的是链接你的收藏家:
Map<String, Map<Integer, List<Person>>> map = people
.collect(Collectors.groupingBy(Person::getName,
Collectors.groupingBy(Person::getAge));
然后,要获得一份名为弗雷德的18岁年轻人名单,您将使用:
map.get("Fred").get(18);
第二个选项是定义表示分组的类。这可以在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);
}
}
然后你可以使用:
Map<NameAge, List<Person>> map = people.collect(Collectors.groupingBy(Person::getNameAge));
并使用
进行搜索map.get(new NameAge("Fred", 18));
最后,如果你不想实现自己的组类,那么很多Java框架都有一个pair
类,专门用于这类事情。例如:apache commons pair如果您使用其中一个库,那么您可以为地图创建一对名称和年龄:
Map<Pair<String, Integer>, List<Person>> map =
people.collect(Collectors.groupingBy(p -> Pair.of(p.getName(), p.getAge())));
并检索:
map.get(Pair.of("Fred", 18));
我个人真的不喜欢这些元组库。它们似乎与良好的OO设计完全相反:它们隐藏意图而不是暴露它。
说过你可以通过定义自己的分组类来组合后两个选项,但只需通过扩展Pair
来实现它 - 这可以节省大量定义equals
等所涉及的工作并隐藏使用元组只是一个方便的实现细节,就像任何其他集合一样。
答案 1 :(得分:28)
这里看代码:
你可以简单地创建一个函数并让它为你完成工作,这是一种功能性的风格!
Function<Person, List<Object>> compositeKey = personRecord ->
Arrays.<Object>asList(personRecord.getName(), personRecord.getAge());
现在您可以将它用作地图:
Map<Object, List<Person>> map =
people.collect(Collectors.groupingBy(compositeKey, Collectors.toList()));
干杯!
答案 2 :(得分:4)
您好您可以简单地连接您的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();
}
答案 3 :(得分:4)
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();
}
}));
现在只需更改输出参数<K>
。例如,在这种情况下,我使用了org.apache.commons.lang3.tuple中的一个配对类,用于按名称和年龄分组,但是您可以根据需要创建自己的类来过滤组。
people.stream().collect(Collectors.groupingBy(new Function<Person, Pair<Integer, String>>() {
@Override
public YourFilter apply(Person person) {
return Pair.of(person.getAge(), person.getName());
}
}));
最后,用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())));
答案 4 :(得分:1)
在组中为键定义定义一个类。
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
}
现在在你的代码中,
peopleByManyParams = people
.collect(Collectors.groupingBy(p -> new KeyObj( p.age, p.other1, p.other2 ), Collectors.mapping((Person p) -> p, toList())));
答案 5 :(得分:1)
您可以将List用作许多字段的分类器,但需要将空值包装到Optional:
Function<String, List> classifier = (item) -> List.of(
item.getFieldA(),
item.getFieldB(),
Optional.ofNullable(item.getFieldC())
);
Map<List, List<Item>> grouped = items.stream()
.collect(Collectors.groupingBy(classifier));
答案 6 :(得分:0)
我需要为一家为各种客户提供午餐的餐饮公司报道。换句话说,餐饮可能有一个或多个从餐饮接受订单的公司,它必须知道它的所有客户每天必须生产多少午餐!
注意,我没有使用排序,以免使这个例子过于复杂。
这是我的代码:
var sessionDetails = JSON.parse($state.params.userid)
答案 7 :(得分:0)
这就是我按照多个字段branchCode和prdId进行分组的方法,只是将其发布给有需要的人
symmetric
输出如下:
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
*
* @author charudatta.joshi
*/
public class Product1 {
public BigInteger branchCode;
public BigInteger prdId;
public String accountCode;
public BigDecimal actualBalance;
public BigDecimal sumActBal;
public BigInteger countOfAccts;
public Product1() {
}
public Product1(BigInteger branchCode, BigInteger prdId, String accountCode, BigDecimal actualBalance) {
this.branchCode = branchCode;
this.prdId = prdId;
this.accountCode = accountCode;
this.actualBalance = actualBalance;
}
public BigInteger getCountOfAccts() {
return countOfAccts;
}
public void setCountOfAccts(BigInteger countOfAccts) {
this.countOfAccts = countOfAccts;
}
public BigDecimal getSumActBal() {
return sumActBal;
}
public void setSumActBal(BigDecimal sumActBal) {
this.sumActBal = sumActBal;
}
public BigInteger getBranchCode() {
return branchCode;
}
public void setBranchCode(BigInteger branchCode) {
this.branchCode = branchCode;
}
public BigInteger getPrdId() {
return prdId;
}
public void setPrdId(BigInteger prdId) {
this.prdId = prdId;
}
public String getAccountCode() {
return accountCode;
}
public void setAccountCode(String accountCode) {
this.accountCode = accountCode;
}
public BigDecimal getActualBalance() {
return actualBalance;
}
public void setActualBalance(BigDecimal actualBalance) {
this.actualBalance = actualBalance;
}
@Override
public String toString() {
return "Product{" + "branchCode:" + branchCode + ", prdId:" + prdId + ", accountCode:" + accountCode + ", actualBalance:" + actualBalance + ", sumActBal:" + sumActBal + ", countOfAccts:" + countOfAccts + '}';
}
public static void main(String[] args) {
List<Product1> al = new ArrayList<Product1>();
System.out.println(al);
al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "001", new BigDecimal("10")));
al.add(new Product1(new BigInteger("01"), new BigInteger("11"), "002", new BigDecimal("10")));
al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "003", new BigDecimal("10")));
al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "004", new BigDecimal("10")));
al.add(new Product1(new BigInteger("01"), new BigInteger("12"), "005", new BigDecimal("10")));
al.add(new Product1(new BigInteger("01"), new BigInteger("13"), "006", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "007", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("11"), "008", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "009", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "010", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("12"), "011", new BigDecimal("10")));
al.add(new Product1(new BigInteger("02"), new BigInteger("13"), "012", new BigDecimal("10")));
//Map<BigInteger, Long> counting = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.counting()));
// System.out.println(counting);
//group by branch code
Map<BigInteger, List<Product1>> groupByBrCd = al.stream().collect(Collectors.groupingBy(Product1::getBranchCode, Collectors.toList()));
System.out.println("\n\n\n" + groupByBrCd);
Map<BigInteger, List<Product1>> groupByPrId = null;
// Create a final List to show for output containing one element of each group
List<Product> finalOutputList = new LinkedList<Product>();
Product newPrd = null;
// Iterate over resultant Map Of List
Iterator<BigInteger> brItr = groupByBrCd.keySet().iterator();
Iterator<BigInteger> prdidItr = null;
BigInteger brCode = null;
BigInteger prdId = null;
Map<BigInteger, List<Product>> tempMap = null;
List<Product1> accListPerBr = null;
List<Product1> accListPerBrPerPrd = null;
Product1 tempPrd = null;
Double sum = null;
while (brItr.hasNext()) {
brCode = brItr.next();
//get list per branch
accListPerBr = groupByBrCd.get(brCode);
// group by br wise product wise
groupByPrId=accListPerBr.stream().collect(Collectors.groupingBy(Product1::getPrdId, Collectors.toList()));
System.out.println("====================");
System.out.println(groupByPrId);
prdidItr = groupByPrId.keySet().iterator();
while(prdidItr.hasNext()){
prdId=prdidItr.next();
// get list per brcode+product code
accListPerBrPerPrd=groupByPrId.get(prdId);
newPrd = new Product();
// Extract zeroth element to put in Output List to represent this group
tempPrd = accListPerBrPerPrd.get(0);
newPrd.setBranchCode(tempPrd.getBranchCode());
newPrd.setPrdId(tempPrd.getPrdId());
//Set accCOunt by using size of list of our group
newPrd.setCountOfAccts(BigInteger.valueOf(accListPerBrPerPrd.size()));
//Sum actual balance of our of list of our group
sum = accListPerBrPerPrd.stream().filter(o -> o.getActualBalance() != null).mapToDouble(o -> o.getActualBalance().doubleValue()).sum();
newPrd.setSumActBal(BigDecimal.valueOf(sum));
// Add product element in final output list
finalOutputList.add(newPrd);
}
}
System.out.println("+++++++++++++++++++++++");
System.out.println(finalOutputList);
}
}
格式化后:
+++++++++++++++++++++++
[Product{branchCode:1, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:1, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:1, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}, Product{branchCode:2, prdId:11, accountCode:null, actualBalance:null, sumActBal:20.0, countOfAccts:2}, Product{branchCode:2, prdId:12, accountCode:null, actualBalance:null, sumActBal:30.0, countOfAccts:3}, Product{branchCode:2, prdId:13, accountCode:null, actualBalance:null, sumActBal:10.0, countOfAccts:1}]