如何使用 Java 8 个流从列表中过滤元素?
How to filter element from a List using Java 8 streams?
我有一个使用 filter()
操作的简单 Java 8 示例。
当我尝试过滤时,得到的是一个空列表。
class Per {
String id;
Per(String id) {
this.id = id;
}
public String getId() {
return id;
}
public static void main(String[] args) {
List<String> allIds = new ArrayList<>();
allIds.add("1");
allIds.add("2");
allIds.add("3");
allIds.add("4");
List<Per> unavailableItems = new ArrayList<>();
unavailableItems.add(new Per("2"));
unavailableItems.add(new Per("4"));
List<Per> ids = unavailableItems.stream().filter(per -> !(allIds.contains(per.getId())))
.collect(Collectors.toList());
System.out.println(ids);// why its returning empty value
}
}
为什么得到一个空列表?
您得到一个空列表,因为操作 filter()
将只在流中保留与给定谓词匹配的元素。
Returns a stream consisting of the elements of this stream that match
the given predicate.
由于源列表中的所有值都存在于 allIds
列表谓词中,因此始终 returns false
.
如果您只想保留 allIds
列表中存在的元素,请将谓词更改为:
filter(per -> allIds.contains(per.getId()))
为了降低 contains()
检查的时间复杂度,您还可以将 allIds
设为 HashSet
。
如果您想进行相反的检查 - 查找可用 id
的列表(id
来自 allIds
列表但不存在于 unavailableItems
) 你可以这样做:
List<String> availableId = allIds.stream()
.filter(id -> unavailableItems.stream()
.noneMatch(pers -> pers.getId() == id))
.collect(Collectors.toList());
如果这就是您要实现的目标,我的建议是通过生成 Map<String, Per>
- person by id 来改进上面的代码availableId
列表。并检查地图中是否不存在 id
而不是遍历整个 availableId
列表。
Map<String, Per> personById = unavailableItems.stream()
.collect(Collectors.toMap(Per::getId, Function.identity()));
List<String> availableId = allIds.stream()
.filter(id -> !personById.containsKey(id))
.collect(Collectors.toList());
你的过滤条件前面有一个不是的符号:
!(allIds.contains(per.getId()))
因此,您不是过滤列表内的项目,而是过滤列表外的项目。您 unavailibleItems 列表仅包含在 allIds 列表中具有匹配项目的项目,这意味着这种情况永远不会成立。但是,如果您删除了非符号,它会起作用,或者如果您将项目添加到 unavailibleItems 列表中,但在 allId 的列表中没有匹配值,它会起作用。
读filter
为:
“我是否应该包括(过滤)这个项目,是或否”
因此,当您的代码执行以下操作时:
List<Per> ids = unavailableItems.stream().filter(per -> !(allIds.contains(per.getId())))
然后你的代码检查它是否应该删除项目 Per("2")
逻辑是“如果allIds
有一个"2"
?那么没有,不过滤它,不包括它(那是您代码中的 !
)
事实上,你没有包括它。
然后用 Per("4")
重复,你也不包含它。
不包括这两个元素的结果是一个空列表。
我希望这有助于澄清它。
您可能认为“filter”的意思是“过滤掉”或“排除”,但恰恰相反。
在我看来,您正试图做相反的事情,从 allIds
中过滤 unavailableItems
中的那些元素
在那种情况下:
List<String> allAvailable = allIds.stream().filter( id -> {
for (Per p : unavailableItems) {
if ( p.getId().equals(id)) {
return false;
}
}
return true;
}).collect(Collectors.toList());
System.out.println(allAvailable);
完全满足您的需求并打印:
[1, 3]
我有一个使用 filter()
操作的简单 Java 8 示例。
当我尝试过滤时,得到的是一个空列表。
class Per {
String id;
Per(String id) {
this.id = id;
}
public String getId() {
return id;
}
public static void main(String[] args) {
List<String> allIds = new ArrayList<>();
allIds.add("1");
allIds.add("2");
allIds.add("3");
allIds.add("4");
List<Per> unavailableItems = new ArrayList<>();
unavailableItems.add(new Per("2"));
unavailableItems.add(new Per("4"));
List<Per> ids = unavailableItems.stream().filter(per -> !(allIds.contains(per.getId())))
.collect(Collectors.toList());
System.out.println(ids);// why its returning empty value
}
}
为什么得到一个空列表?
您得到一个空列表,因为操作 filter()
将只在流中保留与给定谓词匹配的元素。
Returns a stream consisting of the elements of this stream that match the given predicate.
由于源列表中的所有值都存在于 allIds
列表谓词中,因此始终 returns false
.
如果您只想保留 allIds
列表中存在的元素,请将谓词更改为:
filter(per -> allIds.contains(per.getId()))
为了降低 contains()
检查的时间复杂度,您还可以将 allIds
设为 HashSet
。
如果您想进行相反的检查 - 查找可用 id
的列表(id
来自 allIds
列表但不存在于 unavailableItems
) 你可以这样做:
List<String> availableId = allIds.stream()
.filter(id -> unavailableItems.stream()
.noneMatch(pers -> pers.getId() == id))
.collect(Collectors.toList());
如果这就是您要实现的目标,我的建议是通过生成 Map<String, Per>
- person by id 来改进上面的代码availableId
列表。并检查地图中是否不存在 id
而不是遍历整个 availableId
列表。
Map<String, Per> personById = unavailableItems.stream()
.collect(Collectors.toMap(Per::getId, Function.identity()));
List<String> availableId = allIds.stream()
.filter(id -> !personById.containsKey(id))
.collect(Collectors.toList());
你的过滤条件前面有一个不是的符号:
!(allIds.contains(per.getId()))
因此,您不是过滤列表内的项目,而是过滤列表外的项目。您 unavailibleItems 列表仅包含在 allIds 列表中具有匹配项目的项目,这意味着这种情况永远不会成立。但是,如果您删除了非符号,它会起作用,或者如果您将项目添加到 unavailibleItems 列表中,但在 allId 的列表中没有匹配值,它会起作用。
读filter
为:
“我是否应该包括(过滤)这个项目,是或否”
因此,当您的代码执行以下操作时:
List<Per> ids = unavailableItems.stream().filter(per -> !(allIds.contains(per.getId())))
然后你的代码检查它是否应该删除项目 Per("2")
逻辑是“如果allIds
有一个"2"
?那么没有,不过滤它,不包括它(那是您代码中的 !
)
事实上,你没有包括它。
然后用 Per("4")
重复,你也不包含它。
不包括这两个元素的结果是一个空列表。
我希望这有助于澄清它。
您可能认为“filter”的意思是“过滤掉”或“排除”,但恰恰相反。
在我看来,您正试图做相反的事情,从 allIds
中过滤 unavailableItems
在那种情况下:
List<String> allAvailable = allIds.stream().filter( id -> {
for (Per p : unavailableItems) {
if ( p.getId().equals(id)) {
return false;
}
}
return true;
}).collect(Collectors.toList());
System.out.println(allAvailable);
完全满足您的需求并打印:
[1, 3]