我正在尝试根据某个优先级筛选收藏。集合由具有特定类型字段的实体组成。
因此,我想执行以下操作:通过集合进行迭代/流式传输,然后
> < li>
查找具有getType = "type1 "的第一个实体。如果这个实体有价格
找到下一个具有 getType = “type2” 的实体。如果这是有代价的
找到下一个具有 getType = “type3” 的实体。如果这是有代价的
找到下一个具有getType="type4"的实体。如果这有代价
找到下一个具有 getType = “type5” 的实体。如果这是有代价的
否则返回。
我正在尝试使用流来执行此操作,但过滤步骤是我无法创建此优先级过滤类型的地方。我还尝试使用for循环遍历集合,但不确定如何实现type1的findFirst
实体,然后是type2等。
如果您稍微重新表述需求,它会使对流的一系列操作的转换更加清晰——您应该返回带有价格的第一项
MyEntity result = myList.stream()
.filter(e -> e.getPrice() > 0)
.min(Compartor.comparing(MyEntity::getType))
.orElse(null);
原始 - 无效还原方法
一种选择是颠倒操作顺序。例如:过滤其中'价格
stream.filter(elem -> elem.price > 0)
.reduce((elem1, elem2) -> elem1.type.compareTo(elem2.type) < 0 ? elem1 : elem2)
编辑-更正确的还原方法
一般来说,最好保持流操作无状态。因此,创建一个处理遍历列表并返回结果的函数可能是更正确的方法。使用流,可以定义一个自定义的“减速器”,它可以跟踪检查的前一个类型,以确定下一个结果是否是可能的有效匹配。一旦找到有效匹配,它总是被返回。
public static void main(String[] args)
{
List<Entity> data = Arrays.asList(eee(2, 6), eee(1, 0), eee(1, 10), eee(3, 7), eee(2, 0), eee(3, 5), eee(4, 0), eee(5, 0));
System.out.println(data.stream().reduce(new Reducer()).filter(entity -> entity != Reducer.NO_MATCH));
}
/*Once a match is found, always use it. For a given type, only the first found entity of that type will be used*/
public static final class Reducer implements BinaryOperator<Entity>
{
private int priorValidType;
Reducer(){ this.priorValidType = 0; }
@Override
public Entity apply(Entity result, Entity newElem)
{
int nextValidType = priorValidType + 1;
if(priorValidType > 0 && result != NO_MATCH) return result; /*Match already found, use it*/
if(result.type == nextValidType && result.price > 0) { priorValidType = nextValidType; return result; } /*result is a match*/
if(newElem.type == nextValidType && newElem.price > 0) { priorValidType = nextValidType; return newElem; } /*newElem is a match*/
if(result.type == nextValidType || newElem.type == nextValidType) { priorValidType = nextValidType; }
return NO_MATCH; /*No match has been found*/
}
public static final Entity NO_MATCH = new Entity(-1, -1);
}
public static final class Entity
{
private final int price, type;
Entity(int type, int price){ this.price = price; this.type = type; }
public String toString(){ return "(" + type + ", " + price + ")"; }
int getPrice(){ return price; }
int getType(){ return type; }
public static Entity eee(int type, int price){ return new Entity(type, price); }
}
编辑-使用过滤器的替代方法
可以创建一个过滤器,它执行类似于duce方法的操作,并且在调用“findFirst”时具有短路的好处。在下面,第一个过滤器只允许第一次遇到给定类型(按顺序)通过。第二个过滤器确认它是有效的。
public static void main(String[] args)
{
List<Entity> data = Arrays.asList(eee(2, 6), eee(1, 0), eee(1, 10), eee(3, 7), eee(2, 0), eee(3, 5), eee(4, 0), eee(5, 0));
System.out.println(data.stream().filter(new FirstTypeMatch()).filter(entity -> entity.price > 0).findFirst());
}
/*Filter where the element is the first of the given type*/
public static final class FirstTypeMatch implements Predicate<Entity>
{
private int priorValidType = 0;
@Override
public boolean test(Entity nextElem)
{
if(nextElem.type == (priorValidType + 1)){ priorValidType++; return true; }
return false;
}
}
根据Andreas的澄清和对目前所述要求的严格解释,这应该行得通。
类型
进行流式传输,然后对list进行子流式传输
用于验证的类。
class MyClass {
private int price;
private String type;
public MyClass(int price, String type) {
this.price = price;
this.type = type;
}
public int getPrice() {
return price;
}
public String getType() {
return type;
}
public String toString() {
return String.format("[%s, %s]", price, type);
}
}
数据
List<MyClass> list = List.of(new MyClass(0, "Type1"),
new MyClass(10, "Type2"), new MyClass(2, "Type1"),
new MyClass(2, "Type4"), new MyClass(2, "Type5"),
new MyClass(2, "Type2"), new MyClass(10, "Type1"),
new MyClass(1, "Type2"), new MyClass(2, "Type5"));
String[] types =
{ "Type1", "Type2", "Type3", "Type4", "Type5" };
解
MyClass selected = Arrays.stream(types)
.map(type -> list.stream()
.filter(obj -> obj.getType().equals(type))
.findFirst()
.orElse(null))
.filter(a -> a != null && a.getPrice() > 0)
.findFirst().orElse(new MyClass(-1, "Empty"));
System.out.println(selected);
版画
[10, Type2]