簡體   English   中英

如何使用 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()將僅在 stream 中保留與給定謂詞匹配的元素。

返回一個 stream,該 stream 的元素與給定的謂詞相匹配。

由於源列表中的所有值都存在於allIds列表中,因此謂詞始終返回false

如果只想保留allIds列表中存在的元素,請將謂詞更改為:

filter(per -> allIds.contains(per.getId()))

為了降低contains()檢查的時間復雜度,您還可以將allIds設為HashSet


如果你想做相反的檢查——找到可用id的列表(來自allIds列表的id不存在於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是否不存在於 map 中,而不是遍歷整個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());

你的過濾條件前面有一個 not 標志:

!(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")重復,你也不包括它。

不包括這兩個元素的結果是一個空列表。

我希望這有助於澄清它。

您可能認為“過濾”的意思是“過濾掉”或“排除”,但恰恰相反。

在我看來,您正在嘗試做相反的事情,從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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM