我有一个对象列表,让我们说Shapes。 我想使用流处理它们并返回另一个对象 - ShapeType - 基于列表中的内容。
通常我会返回ShapeType.GENERIC,但是如果那里有一个Rectangle,我想返回ShapeType.RECT。如果列表中有六边形,我想返回ShapeType.HEXA。 当存在矩形和正方形时,我想返回ShapeType.HEXA。
现在,谈到代码我想要这样的东西:
public ShapeType resolveShapeType(final List<Shape> shapes) {
shapes.stream()
.filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
// I should have a stream with just rectangles and hexagons if present.
// what now?
}
答案 0 :(得分:5)
您可以使用
public ShapeType resolveShapeType(final List<Shape> shapes) {
int sides = shapes.stream()
.mapToInt(Shape::getSideCount)
.filter(count -> count==4 || count==6)
.max().orElse(0);
return sides==6? ShapeType.HEXA: sides==4? ShapeType.RECT: ShapeType.GENERIC;
}
这会将每个元素映射到其边数并将它们缩减为首选类型,这恰好是此处的最大计数,因此不需要自定义缩减功能。
这不是短路,但对于大多数用例来说,这就足够了。如果你想将操作次数减少到必要的最小值,事情会更复杂。
public ShapeType resolveShapeType(final List<Shape> shapes) {
OptionalInt first = IntStream.range(0, shapes.size())
.filter(index -> {
int count = shapes.get(index).getSideCount();
return count == 6 || count == 4;
})
.findFirst();
if(!first.isPresent()) return ShapeType.GENERIC;
int ix = first.getAsInt(), count = shapes.get(ix).getSideCount();
return count==6? ShapeType.HEXA: shapes.subList(ix+1, shapes.size()).stream()
.anyMatch(shape -> shape.getSideCount()==6)? ShapeType.HEXA: ShapeType.RECT;
}
我们知道我们可以在第一个HEXA
停止,但为了避免第二次通过,有必要记住RECT
是否出现HEXA
的情况没有RECT
}。因此,这会搜索第一个元素,即HEXA
或GENERIC
。如果没有,则返回HEXA
,否则,如果第一个不是HEXA
,则检查其余元素是否为RECT
类的元素。请注意,为了处理第一个filter
之后的余数,不需要RECT
,因为暗示既不是HEXA
也不是for
的形状都无法满足条件。
但同样显而易见的是,这个代码试图最小化检查数量,比同等的<span class=“standout”>
<span class="standout">
循环更难阅读。
答案 1 :(得分:4)
假设列表中只能存在三种形状,则可以选择:
Set<Integer> sides = shapes.stream()
.map(Shape::getSideCount)
.collect(toSet());
if (sides.contains(6)) return HEXA;
else if (sides.contains(4)) return RECTANGLE;
else return GENERIC;
但我认为最简单(也是最有效)的方式对于循环来说是一个很好的旧方法:
ShapeType st = GENERIC;
for (Shape s : shapes) {
if (s.getSideCount() == 6) return HEXA;
if (s.getSideCount() == 4) st = RECTANGLE;
}
return st;
答案 2 :(得分:2)
如果我了解您要执行的操作,则可以使用anyMatch
。像,
public ShapeType resolveShapeType(final List<Shape> shapes) {
if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 6)) {
return ShapeType.HEXA;
} else if (shapes.stream().anyMatch(shape -> shape.getSideCount() == 4)) {
return ShapeType.RECT;
} else {
return ShapeType.GENERIC;
}
}
执行此操作的一种方法(流shapes
一次)将使用数组保留形状存在。像,
public ShapeType resolveShapeType(final List<Shape> shapes) {
boolean[] bits = new boolean[2];
shapes.stream().forEach(shape -> {
int sides = shape.getSideCount();
if (sides == 4) {
bits[0] = true;
} else if (sides == 6) {
bits[1] = true;
}
});
if (bits[1]) {
return ShapeType.HEXA;
} else if (bits[0]) {
return ShapeType.RECT;
} else {
return ShapeType.GENERIC;
}
}
答案 3 :(得分:1)
也可以这样做:
ShapeType
在这里,我对你的enum ShapeType {
Square(4), Hexagon(6), Generic(Integer.MAX_VALUE);
int v;
ShapeType(int v) {
this.v = v;
}
static ShapeType parse(int v) {
switch (v) {
case 4: return Square;
case 6: return Hexagon;
default:
break;
}
return Generic;
}
public String toString(){
return Integer.toString(v);
}
}
:
getShapeType()
如果添加map()
方法,则可以避免解析操作,该方法为每个派生类型返回正确的类型。然后,.map(Shape::getShapeType)
操作将仅提取类型,例如.filter()
。
'/users/'
会找到您感兴趣的群组,最大的形状被视为该系列的标签......
答案 4 :(得分:1)
听起来像'reduce'或'collect / max'。
假设你有一个选择'显性'类型的方法(你可以将它放在一个lambda中,但恕我直言,它作为一种方法更具可读性):
public class Util{
public static ShapeType dominantType(ShapeType t1, ShapeType t2){
if(t1==HEXA || t2==HEXA) return HEXA;
else if (t1==RECTANGLE || t2==RECTANGLE) return RECTANGLE;
else return GENERIC;
}
}
有几种方法可以使用它,一个简化示例是:
shapes.stream()
.filter(shape -> shape.getSideCount() == 6 || shape.getSideCount() == 4)
.map(shape -> shape.getSideCount()==6? HEXA:RECTANGLE)
.reduce( GENERIC, Util::dominantType);
// using GENERIC in case of empty list
您可能还想查看collectors.maxBy。 顺便说一句,无论你采取什么方法,请在空列表的情况下考虑一下行为......