使用java 8迭代和过滤两个列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/29490418/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:05:14  来源:igfitidea点击:

iterating and filtering two lists using java 8

javafilter

提问by Arun Khot

I want to iterate two lists and get new filtered list which will have values not present in second list. Can anyone help?

我想迭代两个列表并获取新的过滤列表,该列表的值将不存在于第二个列表中。任何人都可以帮忙吗?

I have two lists - one is list of strings, and the other is list of MyClassobjects.

我有两个列表——一个是字符串列表,另一个是MyClass对象列表。

List<String> list1;
List<MyClass> list2;

MyClass {

    MyClass(String val)
    {
        this.str = val;
    }

     String str;
     ...
     ...
}

I want filtered list of strings based on -> check second list for elements (abc) whose values not present in list1.

我想要基于过滤的字符串列表 -> 检查其值不存在于list1.

List<String> list1 = Arrays.asList("abc", "xyz", "lmn");

List<MyClass> list2 = new ArrayList<MyClass>();

MyClass obj = new MyClass("abc");
list2.add(obj);
obj = new MyClass("xyz");
list2.add(obj);

Now I want new filtered list -> which will have value => "lmn". i.e. values not present in list2whose elements are in list1.

现在我想要新的过滤列表 -> 它将具有值 =>“lmn”。即不存在list2于其元素中的值list1

采纳答案by Arun Khot

Finally I got way to achieve this following way -

最后我有办法实现以下方式 -

List<String> unavailable = list1.stream()
                .filter(e -> (list2.stream()
                        .filter(d -> d.getStr().equals(e))
                        .count())<1)
                        .collect(Collectors.toList());

But this is also working as expected. Please let me know how much this is effective? and if anyone has other way to do same thing?

但这也按预期工作。请让我知道这有多有效?如果有人有其他方法可以做同样的事情?

回答by Ashley Frieze

If you stream the first list and use a filter based on contains within the second...

如果您流式传输第一个列表并使用基于包含在第二个列表中的过滤器...

list1.stream()
    .filter(item -> !list2.contains(item))

The next question is what code you'll add to the end of this streaming operation to further process the results... over to you.

下一个问题是您将在此流操作的末尾添加什么代码以进一步处理结果……交给您。

Also, list.contains is quite slow, so you would be better with sets.

此外, list.contains 很慢,所以你会更好地使用集合。

But then if you're using sets, you might find some easier operations to handle this, like removeAll

但是如果你使用集合,你可能会发现一些更简单的操作来处理这个,比如 removeAll

Set list1 = ...;
Set list2 = ...;
Set target = new Set();
target.addAll(list1);
target.removeAll(list2);

Given we don't know how you're going to use this, it's not really possible to advise which approach to take.

鉴于我们不知道您将如何使用它,因此不太可能建议采取哪种方法。

回答by Ashley Frieze

// produce the filter set by streaming the items from list 2
// assume list2 has elements of type MyClass where getStr gets the
// string that might appear in list1
Set<String> unavailableItems = list2.stream()
    .map(MyClass::getStr)
    .collect(Collectors.toSet());

// stream the list and use the set to filter it
List<String> unavailable = list1.stream()
            .filter(e -> unavailableItems.contains(e))
            .collect(Collectors.toList());

回答by tosi

See below, would welcome anyones feedback on the below code.

见下文,欢迎任何人对以下代码提供反馈。

not common between two arrays:

两个数组之间不常见:

List<String> l3 =list1.stream().filter(x -> !list2.contains(x)).collect(Collectors.toList());

Common between two arrays:

两个数组之间的共同点:

List<String> l3 =list1.stream().filter(x -> list2.contains(x)).collect(Collectors.toList());

回答by DSchmidt

Doing it with streams is easy and readable:

使用流来做这件事很容易且可读:

Predicate<String> notIn2 = s -> ! list2.stream().anyMatch(mc -> s.equals(mc.str));
List<String> list3 = list1.stream().filter(notIn2).collect(Collectors.toList());

回答by YiFu.Zhou

list1 = list1.stream().filter(str1-> 
        list2.stream().map(x->x.getStr()).collect(Collectors.toSet())
        .contains(str1)).collect(Collectors.toList());

This may work more efficient.

这可能更有效。

回答by Ran Adler

if you have class with id and you want to filter by id

如果你有带 id 的类并且你想按 id 过滤

line1 : you mape all the id

line1 : 你映射所有的 id

line2: filter what is not exist in the map

line2:过滤地图中不存在的内容

Set<String> mapId = entityResponse.getEntities().stream().map(Entity::getId).collect(Collectors.toSet());

List<String> entityNotExist = entityValues.stream().filter(n -> !mapId.contains(n.getId())).map(DTOEntity::getId).collect(Collectors.toList());

回答by Joey587

@DSchmdit answer worked for me. I would like to add on that. So my requirement was to filter a file based on some configurations stored in the table. The file is first retrieved and collected as list of dtos. I receive the configurations from the db and store it as another list. This is how I made the filtering work with streams

@DSchmdit 答案对我有用。我想补充一点。所以我的要求是根据存储在表中的一些配置过滤文件。该文件首先被检索并收集为 dtos 列表。我从数据库接收配置并将其存储为另一个列表。这就是我使用流进行过滤的方式

    List<FPRSDeferralModel> modelList = Files
            .lines(Paths.get("src/main/resources/rootFiles/XXXXX.txt")).parallel().parallel()
            .map(line -> {
                FileModel fileModel= new FileModel();
                line = line.trim();
                if (line != null && !line.isEmpty()) {
                    System.out.println("line" + line);
                    fileModel.setPlanId(Long.parseLong(line.substring(0, 5)));
                    fileModel.setDivisionList(line.substring(15, 30));
                    fileModel.setRegionList(line.substring(31, 50));
                    Map<String, String> newMap = new HashedMap<>();
                    newMap.put("other", line.substring(51, 80));
                    fileModel.setOtherDetailsMap(newMap);

                }
                return fileModel;
            }).collect(Collectors.toList());

    for (FileModel model : modelList) {
        System.out.println("model:" + model);
    }

    DbConfigModelList respList = populate();
    System.out.println("after populate");
    List<DbConfig> respModelList = respList.getFeedbackResponseList();


    Predicate<FileModel> somePre = s -> respModelList.stream().anyMatch(respitem -> {

        System.out.println("sinde respitem:"+respitem.getPrimaryConfig().getPlanId());
        System.out.println("s.getPlanid()"+s.getPlanId());
        System.out.println("s.getPlanId() == respitem.getPrimaryConfig().getPlanId():"+
        (s.getPlanId().compareTo(respitem.getPrimaryConfig().getPlanId())));
        return s.getPlanId().compareTo(respitem.getPrimaryConfig().getPlanId()) == 0
                && (s.getSsnId() != null);
    });



 final List<FileModel> finalList =  modelList.stream().parallel().filter(somePre).collect(Collectors.toList());

 finalList.stream().forEach(item -> {
     System.out.println("filtered item is:"+item);
 });

The details are in the implementation of filter predicates. This proves much more perfomant over iterating over loops and filtering out

细节在过滤谓词的实现中。这证明比循环迭代和过滤更高效

回答by Vignesh

`List<String> unavailable = list1.stream()
                .filter(e -> (list2.stream()
                        .filter(d -> d.getStr().equals(e))
                        .count())<1)
                        .collect(Collectors.toList());`
for this if i change to 
`List<String> unavailable = list1.stream()
                .filter(e -> (list2.stream()
                        .filter(d -> d.getStr().equals(e))
                        .count())>0)
                        .collect(Collectors.toList());`
will it give me list1 matched with list2 right?