通过多次检查过滤与谓词匹配的第一个元素

我正在尝试使用流过滤具有两个不同谓词的 POJO 列表。


public class Toy {

  public boolean isRed();

  public boolean isBlue();

  public boolean isGreen();

}


public class RedBlueExtravaganza {

  public RedBlueExtravaganza(RedToy rt, BlueToy bt) {

    //construct

  }

}


// Wrappers around Toy with more verbose names

public class RedToy extends Toy { }

public class BlueToy extends Toy { }

public class GreenToy extends Toy { }

基本上,我想要玩具对象列表中的第一个红色和第一个蓝色玩具。


List<Toy> toyList = Arrays.asList(greenToy1, redToy1, greenToy2, redToy2, blueToy1);

我想编写一个执行以下操作的流:


RedBlueExtravaganza firstRedBlueList = toyList.stream()

       // get first red but keep rest of list

       // get first blue but keep rest of list

       // discard rest of list

       // map to a Tuple (or something) to distinguish the one red and one blue toy

       // map to RedBlueExtravaganza

       .findFirst()

       .get();


log.info(firstRedBlueList); // now contains redToy1, blueToy1

谢谢您的帮助!


泛舟湖上清波郎朗
浏览 109回答 3
3回答

呼唤远方

这是一个仅遍历列表一次的解决方案,在最后为您提供第一个红色和蓝色玩具。我们可以过滤掉所有其他不相关的颜色,然后创建一个映射,其键是玩具是否是红色,值是符合给定条件的第一个玩具。它看起来是这样的。Map<Boolean, Toy> firstRedAndBlueToysMap = toyList.stream()&nbsp; &nbsp; .filter(t -> t.isBlue() || t.isRed())&nbsp; &nbsp; .collect(Collectors.toMap(Toy::isRed, t -> t, (a, b) -> a));Toy firstRedToy = firstRedAndBlueToysMap.get(true);Toy firstBlueToy = firstRedAndBlueToysMap.get(false);这是解决您问题的一步法。RedBlueExtravaganza firstRedAndBlueToyPair = toyList.stream()&nbsp; &nbsp; .filter(t -> t.isBlue() || t.isRed())&nbsp; &nbsp; .collect(Collectors.collectingAndThen(Collectors.toMap(Toy::isRed,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;t -> t, (a, b) -> a),&nbsp; &nbsp; &nbsp; &nbsp; m -> new RedBlueExtravaganza(m.get(true), m.get(false))));PS 为此,您需要在RedBlueExtravaganza类中拥有以下构造函数,与上面提供的构造函数相反。public RedBlueExtravaganza(Toy rt, Toy bt) {&nbsp; &nbsp; if (!(rt instanceof RedToy) || !(bt instanceof BlueToy))&nbsp; &nbsp; &nbsp; &nbsp; throw new IllegalArgumentException();&nbsp; &nbsp; // remainder omitted.}

慕标5832272

类似的解决方案可以是减少并列出为“元组(或其他)”List<Toy> reduceToList = toyList.stream()      .filter(t -> t.isBlue() || t.isRed())      .map(t -> Arrays.asList(t, t))      .reduce(Arrays.asList(null, null), (a, c) -> a.get(0) == null && c.get(0).isRed() ?              Arrays.asList(c.get(0), a.get(1)) : (a.get(1) == null && c.get(1).isBlue() ?              Arrays.asList(a.get(0), c.get(1)) : a)      );如果两个值都不为空,那么您可以映射到RedBlueExtravaganza

隔江千里

我首先想到的一种方法是使用 2 个流分别查找第一个红色和蓝色玩具对象。然后通过使用将它们合并到一个流中,Stream.concat()以便您可以为此添加更多操作。代码片段RedBlueExtravaganza firstRedBlueList = Stream&nbsp; &nbsp; .concat(&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toyList.stream().filter(t -> t.isRed())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .findFirst()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(Collections::singletonList)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .orElseGet(Collections::emptyList)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .stream(),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; toyList.stream().filter(t -> t.isBlue())&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .findFirst()&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .map(Collections::singletonList)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .orElseGet(Collections::emptyList)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .stream())&nbsp; &nbsp; .map(x -> {&nbsp; &nbsp; &nbsp; &nbsp; RedToy rt = new RedToy();&nbsp; &nbsp; &nbsp; &nbsp; BlueToy bt = new BlueToy();&nbsp; &nbsp; &nbsp; &nbsp; ...&nbsp; &nbsp; &nbsp; &nbsp; return new RedBlueExtravaganza(rt, bt);})&nbsp; &nbsp; .findFirst()&nbsp; &nbsp; .get();
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java