原始 - 无效的缩减方法
一种选择是翻转操作顺序。例如:过滤“价格> 0”的位置,然后在遇到元素时减少流。例如:
stream.filter(elem -> elem.price > 0)
.reduce((elem1, elem2) -> elem1.type.compareTo(elem2.type) < 0 ? elem1 : elem2)
编辑 - 更正确的缩减方法
一般来说,最好保持流操作无状态。因此,创建一个处理遍历列表并返回结果的函数可能是一种更正确的方法。使用流,可以定义一个自定义的“reducer”,它跟踪检查的先前类型以确定下一个结果是否是可能的有效匹配。一旦找到一个有效的匹配,它总是被返回。
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); }
}
编辑 - 使用过滤器的替代方法
可以创建一个过滤器,它执行类似于reduce 方法的操作,并且在调用“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;
}
}