根据其ID删除对象,并收集已删除到另一个列表的对象

发布于 2025-02-09 06:25:12 字数 2878 浏览 0 评论 0 原文

我想从雇员的列表中删除( list1 )对象,该对象在雇员的另一个列表中不存在代码>)通过其 ID ,然后使用Java8。

示例:

List<Employee> list1 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("300","pleasanton","California"),
                        new Employee("200","Decatur","Texas"),
                        new Employee("500","Cumming","Atlanta"),
                        new Employee("98","sula","Maine"),
                        new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

从上面的列表中,需要基于 ID 对象 iD 。

List<Employee> list2 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("800","pleasanton","California"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("10","Decatur","Texas"),
                        new Employee("500","Cumming","Atlanta"),
                        new Employee("50","sula","Maine"),
                        new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

预期输出: List1和List3

       List<Employee> list1 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("500","Cumming","Atlanta"),
                new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

        List<Employee> list3 = Stream.of(
                        new Employee("300","pleasanton","California"),
                        new Employee("200","Decatur","Texas"),
                        new Employee("98","sula","Maine")
                        )
                .collect(Collectors.toList());

在下面尝试过,但无法按预期工作

        List<Employee> list3 = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(list1) && CollectionUtils.isNotEmpty(list2)){
            list2.stream().forEachOrdered( l2 -> {
                Optional<Employee> nonMatch = list1.stream().filter(l1 -> !l1.getId().equalsIgnoreCase(l2.getId())).findAny();
                if(nonMatch.isPresent()){
                    list3.add(nonMatch.get());
                    list1.removeIf(l1 -> l1.getId().equalsIgnoreCase(nonMatch.get().getId()));
                }
            });
        }

        System.out.println(list1);
        System.out.println(list3);

I want to remove from a list of Employee (list1) objects that are not present in another list of Employee (list2) by their id and add removed objects from list1 into another list (list3) using Java 8.

Example :

List<Employee> list1 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("300","pleasanton","California"),
                        new Employee("200","Decatur","Texas"),
                        new Employee("500","Cumming","Atlanta"),
                        new Employee("98","sula","Maine"),
                        new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

From the above list need to remove Employee object based on id of below list.

List<Employee> list2 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("800","pleasanton","California"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("10","Decatur","Texas"),
                        new Employee("500","Cumming","Atlanta"),
                        new Employee("50","sula","Maine"),
                        new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

Expected Output :
list1 and list3

       List<Employee> list1 = Stream.of(
                        new Employee("100","Boston","Massachusetts"),
                        new Employee("400","Atlanta","Georgia"),
                        new Employee("500","Cumming","Atlanta"),
                new Employee("156","Duluth","Ohio"))
                .collect(Collectors.toList());

        List<Employee> list3 = Stream.of(
                        new Employee("300","pleasanton","California"),
                        new Employee("200","Decatur","Texas"),
                        new Employee("98","sula","Maine")
                        )
                .collect(Collectors.toList());

Tried below way but not working as expected

        List<Employee> list3 = new ArrayList<>();
        if(CollectionUtils.isNotEmpty(list1) && CollectionUtils.isNotEmpty(list2)){
            list2.stream().forEachOrdered( l2 -> {
                Optional<Employee> nonMatch = list1.stream().filter(l1 -> !l1.getId().equalsIgnoreCase(l2.getId())).findAny();
                if(nonMatch.isPresent()){
                    list3.add(nonMatch.get());
                    list1.removeIf(l1 -> l1.getId().equalsIgnoreCase(nonMatch.get().getId()));
                }
            });
        }

        System.out.println(list1);
        System.out.println(list3);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

◇流星雨 2025-02-16 06:25:12

这是两个可能的解决方案。

这是简短而简洁的,但实际上并没有从 List1 中删除元素,而是利用分区收集器来创建两个列表。将分区的收藏家视为一种双向过滤器:如果您的谓词满足,请收集到一个列表,如果不是,请收集到另一个列表。在我们的情况下,谓词实际上是“ List2是否包含一个与List1相同的ID的员工?”。为了降低实际开销,该代码从 list2 forront准备了ID列表。

        final List<String> list2Ids = list2.stream()
                .map(Employee::getId)
                .collect(Collectors.toList());

        Map<Boolean, List<Employee>> partitioned = list1.stream()
                .collect(Collectors.partitioningBy(e -> list2Ids.contains(e.getId())));

        list1 = partitioned.get(true);
        List<Employee> list3 = partitioned.get(false);

如果您需要保留 list1 - 例如出于内存脚印的原因 - 并且确实必须从中删除元素,我会说您必须坚持使用真正的老式迭代器。这样做的原因是迭代器允许您在此过程中迭代某些集合删除元素。下一个样本完全做到这一点。请注意,我再次准备了 list2 的ID列表。

        final List<String> list2Ids = list2.stream()
                .map(Employee::getId)
                .collect(Collectors.toList());

        final List<Employee> list3 = new LinkedList<>();

        for (Iterator<Employee> iterator = list1.iterator(); iterator.hasNext();) {
            Employee next = iterator.next();

            if (!list2Ids.contains(next.getId())) {
                list3.add(next);
                iterator.remove();
            }
        }

Here come two possible solutions.

This one is short and concise, but does in fact not remove elements from list1 but utilizes a partitioning collector to create the two lists. Think of the partitioning collector as kind of a two-way filter: if your predicate is fulfilled, collect to one list, if it's not, collect to the other list. The predicate in our case actually is "does list2 contain an employee with the same ID as the stream element from list1?". In order to lower the actual overhead, the code prepares a list of IDs from list2 up-front.

        final List<String> list2Ids = list2.stream()
                .map(Employee::getId)
                .collect(Collectors.toList());

        Map<Boolean, List<Employee>> partitioned = list1.stream()
                .collect(Collectors.partitioningBy(e -> list2Ids.contains(e.getId())));

        list1 = partitioned.get(true);
        List<Employee> list3 = partitioned.get(false);

If you need to keep list1 - e.g. for memory foot-print reasons - and really have to remove the elements from it, I'd say you will have to stick to the really old-fashioned iterator. The reason for that is that iterators allow you to iterate some collection and remove elements while doing so. The next sample does exactly this. Note, that I prepared a list of IDs of list2 up-front again.

        final List<String> list2Ids = list2.stream()
                .map(Employee::getId)
                .collect(Collectors.toList());

        final List<Employee> list3 = new LinkedList<>();

        for (Iterator<Employee> iterator = list1.iterator(); iterator.hasNext();) {
            Employee next = iterator.next();

            if (!list2Ids.contains(next.getId())) {
                list3.add(next);
                iterator.remove();
            }
        }

酒儿 2025-02-16 06:25:12

当前代码的问题:

  • 记住是经验法则:每次您发现自己使用 foreach 在流外更改某些东西时,很可能出现了问题(*请看一下 api文档 。 循环的普通没有任何优势。
  • > foreach()对 /wiki/self-documenting_code“ rel =“ nofollow noreferrer”> 自我解释的名称 。喜欢 empldeparmentx empleolddb 等名称 list1 更难

在代码上解决此问题( 时间复杂性):

  • 创建 ID>的 id 的 中包含的 list2 剩余:包含的时间复杂性检查是 o(1));
  • employee 的列表中生成 list1 中没有常见 ID> ID noncommonid 中的) 雇员 list2 中包含在 list1 的每个 id 中, set set 在上一步获得。
  • 从列表中删除具有不同 ID 的员工会单独导致额外的性能开销,因为每个删除都有线性时间的复杂性。一个更好的选择是使用 removeAll()
  • 在列表上应用 removeAll() id 丢弃了上一步中获得的列表中存在的所有员工。

总体时间复杂性 o(n + m) n m - 是 list1 中的元素数字和 list2 )。

Set<String> idSet = list2.stream()
    .map(Employee::id)
    .collect(Collectors.toSet());
            
List<Employee> nonCommonId = list1.stream()
    .filter(emp ->  !idSet.contains(emp.id()))
    .collect(Collectors.toList());
            
list1.removeAll(new HashSet<>(nonCommonId)); // list `nonCommonId` is wrapped by the HashSet to improve performance, because `removeAll()` relies on the `contains()` checks
// diplaying results
System.out.println("List1:");
list1.forEach(System.out::println);
            
System.out.println("nonCommonId:");
nonCommonId.forEach(System.out::println);

输出:

List1:
Employee[id=100, city=Boston, state=Massachusetts]
Employee[id=400, city=Atlanta, state=Georgia]
Employee[id=500, city=Cumming, state=Atlanta]
Employee[id=156, city=Duluth, state=Ohio]
nonCommonId:
Employee[id=300, city=pleasanton, state=California]
Employee[id=200, city=Decatur, state=Texas]
Employee[id=98, city=sula, state=Maine]

链接到在线演示

Issues with your current code:

  • Remember as the rule of thumb: every time you're finding yourself changing something outside the stream using forEach, most likely something is going wrong (*have a look at the API documentation. You can invoke forEach() method on any type of collection without creating a stream, but keep in mind that using a multiline lambda inside forEach() doesn't bring you any advantage over a plain for loop.
  • it's highly advisable to give your variable clear self-explanatory names. Like emplDeparmentX, empleOldDB, etc. Names list1 makes more difficult to reason about the code.

You can address this problem in the following steps (time complexity of each step is linear):

  • create a Set of id contained in the list2 (remainder: the time complexity of the contains check is O(1));
  • generate the list of Employee (denoted as nonCommonId in the code) from the list1 that have no common id with Employee contained in the list2 by checking every id from the list1 against the Set obtained at the previous step.
  • Removing employees with different id from a list separately causes additional performance overhead because each removal has a linear time complexity. A better option will be to use removeAll().
  • apply removeAll() on the list id discard all the employee that are present in the list obtained at the previous step.

The overall time complexity O(n + m) (n and m - are numbers of elements in the list1 and list2).

Set<String> idSet = list2.stream()
    .map(Employee::id)
    .collect(Collectors.toSet());
            
List<Employee> nonCommonId = list1.stream()
    .filter(emp ->  !idSet.contains(emp.id()))
    .collect(Collectors.toList());
            
list1.removeAll(new HashSet<>(nonCommonId)); // list `nonCommonId` is wrapped by the HashSet to improve performance, because `removeAll()` relies on the `contains()` checks
// diplaying results
System.out.println("List1:");
list1.forEach(System.out::println);
            
System.out.println("nonCommonId:");
nonCommonId.forEach(System.out::println);

Output:

List1:
Employee[id=100, city=Boston, state=Massachusetts]
Employee[id=400, city=Atlanta, state=Georgia]
Employee[id=500, city=Cumming, state=Atlanta]
Employee[id=156, city=Duluth, state=Ohio]
nonCommonId:
Employee[id=300, city=pleasanton, state=California]
Employee[id=200, city=Decatur, state=Texas]
Employee[id=98, city=sula, state=Maine]

A link to Online Demo

活泼老夫 2025-02-16 06:25:12

首先从List2获取不同的ID列表2

idList = list2.stream().map(Employee::getID).distinct().collect(Collectors.toList())

删除具有从list1的通用ID的员工并获取List3。

ArrayList<Employee> list3 =  list1.stream().filter(e->!idList .contains(e.getID())).collect(Collectors.toList());


list1 = list1.stream().filter(e->idList.contains(e.getID())).collect(Collectors.toList());

First get the distinct id list from list2

idList = list2.stream().map(Employee::getID).distinct().collect(Collectors.toList())

Remove the employees having common id from list1 and get list3.

ArrayList<Employee> list3 =  list1.stream().filter(e->!idList .contains(e.getID())).collect(Collectors.toList());


list1 = list1.stream().filter(e->idList.contains(e.getID())).collect(Collectors.toList());

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文