假设我们有一个 3 维对象列表:
class OneDObject {
int id;
List<Integer> list;
OneDObject(int id, List<Integer>list) { /* Constructor */ }
// Getters and Setters
}
class TwoDObject {
int id;
List<OneDObject> list;
TwoDObject(int id, List<OneDObject> list) { /* Constructor */ }
// Getters and Setters
}
var l1 = List.of(1,2,4);
var l2 = List.of(2,4,6);
var obj1d1 = new OneDObject(1, l1);
var obj1d2 = new OneDObject(2, l2);
var l3 = List.of(obj1d1, obj1d2);
var l4 = List.of(obj1d1);
var obj2d1 = new TwoDObject(3, l3);
var obj2d2 = new TwoDObject(4, l4);
var l5 = List.of(obj2d1, obj2d2); // 3-d list
假设我想过滤“l5”,这样如果最里面的列表中的任何元素是奇数,则应删除整个列表,如果这使得第二级列表为空,则应将其删除.
因此,对于给定的示例,在过滤之前:
[[[1,2,4],[2,4,6]], [[1,2,4]]]
过滤后应该是:
[[[2,4,6]]]
如何使用 Java 中的流来做到这一点?
由于您需要更新列表,因此在下面的解决方案中,我使用
removeIf
的 List
方法来删除任何不符合必要条件的元素。因此,为了让 removeIf
发挥作用,列表不应该是一成不变的。因此将 var list = List.of(...)
代码替换为 var list = new ArrayList<>(List.of(...));
(注意:空检查也被忽略。)
现在,这个问题可以分解为几个部分:
Predicate<OneDObject> hasOdd = obj-> obj.getList().stream().anyMatch(i -> i % 2 != 0);
Predicate<TwoDObject> validate2d = obj -> {
// remove any 1d list that has atleast one odd number.
obj.getList().removeIf(hasOdd);
// check if there are any valid 1d lists
return obj.getList().isEmpty();
};
l5.removeIf(validate2d); // l5 will now contain only the 2d object having [2,4,6] list
这是最终代码(Java 语言,但我认为它应该几乎可以与 Kotlin 互换)
List<TwoDObject> l6 = l5.stream()
.peek(twoDObject -> {
List<OneDObject> filteredOneDObjectList = twoDObject.getList()
.stream()
.filter(oneDObject -> oneDObject.getList()
.stream()
.noneMatch(i -> i % 2 == 1))
.toList();
twoDObject.setList(filteredOneDObjectList);
})
.filter(twoDObject -> twoDObject.getList().size() > 0)
.toList();
首先,我们通过调用
twoDObject
来遍历每个 Stream#peek
,然后流式传输其列表并过滤掉每个包含奇数的 oneDObject。然后列表被保存回当前的twoDObject。
最后我们过滤掉所有空的twoDObject。
请注意,
Stream#peek
通常仅用于调试目的,而不是改变流元素。
List<TwoDObject> l6 = l5.stream()
.map(twoDObject -> {
...
return twoDObject;
})
...
如果您实际上并不关心改变列表并保留起始
TwoDObject
对象,并且创建新对象是可以接受的,则以下命令将返回所需的结果:
List<TwoDObject> filtered = l5.stream()
.map(do2 -> new TwoDObject(do2.getId(), do2.getList().stream().filter(
do1 -> do1.getList().stream().noneMatch(e -> e % 2 == 1)).toList()))
.filter(do2 -> !do2.getList().isEmpty())
.toList();
这会为列表中的每个元素创建新的
TwoDObject
复制值,但其 list
值会被过滤为仅包含不包含奇数的 OneDObject
值。 然后,它会过滤掉列表中剩余零个项目的任何新 TwoDObject
值(即每个 TwoDObject
,其中所有 OneDObject
元素都已被上一步过滤掉)。