一尘不染

Java 8流:从一个列表中查找与根据另一列表中的值计算得出的条件相匹配的项目

java

有两个类和两个对应的列表:

class Click {
   long campaignId;
   Date date;
}

class Campaign {
   long campaignId;
   Date start;
   Date end;
   String type;
}

List<Click> clicks = ..;
List<Campaign> campaigns = ..;

而要查找所有Click以s clicks说:

  1. 有一个对应Campaigncampaigns列表,即,Campaign具有相同的campaignIdAND

  2. Campaign具有type“预期”且

  3. Campaigns.start< click.date<Campaigns.end

到目前为止,我有以下实现(对我来说似乎令人困惑和复杂):

clicks.
        stream().
        filter(click -> campaigns.stream().anyMatch(
                campaign -> campaign.getCampaignType().equals("prospecting") &&
                        campaign.getCampaignId().equals(click.getCampaignId()) &&
                        campaign.getStart().after(click.getDate()) &&
                        campaign.getEnd().before(click.getDate()))).
        collect(toList());

我想知道是否有更简单的解决方案。


阅读 320

收藏
2020-12-03

共1个答案

一尘不染

突出的一件事是您的第二个要求与匹配无关,这只是一个条件campaigns。您必须测试这是否对您更好:

clicks.stream()
    .filter(click -> campaigns.stream()
        .filter(camp -> "prospecting".equals(camp.type))
        .anyMatch(camp -> 
            camp.campaignId == click.campaignId &&
            camp.end.after(click.date) &&
            camp.start.before(click.date)
        )
    )
    .collect(Collectors.toList());

否则,我从未见过不涉及在第一个谓词内部流式传输第二个集合的流解决方案,因此您做不到的事不会比您做的更好。在可读性方面,如果您感到困惑,则创建一个测试布尔条件的方法并调用它:

clicks.stream()
    .filter(click -> campaigns.stream()
        .filter(camp -> "pre".equals(camp.type))
        .anyMatch(camp -> accept(camp, click))
    )
    .collect(Collectors.toList());

static boolean accept(Campaign camp, Click click) {
    return camp.campaignId == click.campaignId &&
            camp.end.after(click.date) &&
            camp.start.before(click.date);
}

最后,有2条无关的建议:

  1. 不要使用旧的Date类,而要使用新的java.time APILocalDate
  2. 如果Campaigntype只能有一些预定义的值(如‘提交’,‘探矿’,‘接受’…),那么enum会比一般更适合String
2020-12-03