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

新手上路,请多包涵

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

 class Click {
   long campaignId;
   Date date;
}

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

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

并希望在 --- 中找到所有 Click clicks

  1. 有一个 campaignId Campaign Campaign campaigns

  2. 这个 Campaigntype =“预期”和

  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());

我想知道是否有更简单的解决方案来解决这个问题。

原文由 Andrey Yaskulsky 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 359
2 个回答

突出的一件事是您的第二个要求与匹配无关,它只是 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 更合适。

原文由 user1803551 发布,翻译遵循 CC BY-SA 3.0 许可协议

好吧,有一种非常巧妙的方法可以解决您的问题 IMO,最初的想法来自 Holger(我会找到问题并将其链接到此处)。

您可以定义执行检查的方法(我稍微简化了它):

 static boolean checkClick(List<Campaign> campaigns, Click click) {
    return campaigns.stream().anyMatch(camp -> camp.getCampaignId()
               == click.getCampaignId());
}

并定义一个绑定参数的函数:

 public static <T, U> Predicate<U> bind(BiFunction<T, U, Boolean> f, T t) {
    return u -> f.apply(t, u);
}

用法是:

 BiFunction<List<Campaign>, Click, Boolean> biFunction = YourClass::checkClick;
Predicate<Click> predicate = bind(biFunction, campaigns);

clicks.stream()
      .filter(predicate::test)
      .collect(Collectors.toList());

原文由 Eugene 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题