Java自定义分组与||条件

时间:2017-05-02 18:38:16

标签: java java-8 java-stream collectors

我想知道我是否可以通过多个键进行分组。 让我说我上了一堂课:

Class Something {
    String name;
    String id;
}

以及一系列事项:

  Name     id

  David    123
  David    456
  Bryant   123
  Ryan     456
  Foo      555
  Bar      555

我可以将它们分组到

[(David, 123), (David, 456), (Bryant, 123), (Ryan, 456)]
[(Foo, 555), (Bar, 555)]

这意味着,我想要的类“等于”的行为是名称或者id是相同的,类等于,这样

public boolean equals(Object o) {
    Something that = (Something) o;
    return this.name.equals(that.name) || this.id.equals(that.id);
}

但是equals函数的问题是不可传递的,这意味着我无法为它编写相应的hashCode函数。

我知道如果我写两个哈希图,我可以通过

来实现
Map<String, Something> idToSomething;
Map<String, Something> nameToSomething;

现在的问题是,我应该如何通过使用Collections来实现我想要的行为,比如说这些东西是在名为somethings的List中,所以我可以做类似的事情

somethings.stream().collect(Collectors.groupby(???))

注意我也希望能够改变???通过策略应用不同的分组,将来很容易说,我可能希望将来按名称或ID进行分组。

2 个答案:

答案 0 :(得分:0)

解决此问题的一种方法是创建一个方法,确定Function<? super Something, ? extends String>作为分类器传递给Collectors#groupingBy并使用全局变量来确定应该使用哪个:

private boolean shouldIdBeUsed = true;

public Function<? super Something, ? extends String> getClassifier() {
    if (shouldIdBeUsed) {
        return Something::getId;
    }

    return Something::getName;
}

现在,您只需将该方法作为参数传递:

somethings.stream().collect(Collectors.groupingBy(getClassifier()));

答案 1 :(得分:0)

Jacob的扩展答案。

        Map<UUID, List<BookingOutput.CostsQuoteSummary>> quotesPerUsers = bookings.stream()
            .map(booking -> new BookingOutput.CostsQuoteSummary(
                    booking,
                    timesheet.getDates().getFrom(),
                    timesheet.getDates().getTo()
            ))
            .collect(Collectors.groupingBy(groupCostsPerUser(uuidGenerator)));

我们在其中添加了groupCostsPerUser(uuidGenerator)方法,该方法封装了我们所需的任何条件。以我为例:

private Function<BookingOutput.CostsQuoteSummary, UUID> groupCostsPerUser(UUIDGenerator uuidGenerator) {
    return costsQuoteSummary -> costsQuoteSummary.hasUserId() ? costsQuoteSummary.getUserId()
            : uuidGenerator.generateV4(); 
}