从列表中获取和删除元素。

时间:2021-08-04 20:17:11

Given a list of elements, I want to get the element with a given property and remove it from the list. The best solution I found is:

给定一个元素列表,我希望获得具有给定属性的元素并将其从列表中删除。我找到的最好的解决办法是:

ProducerDTO p = producersProcedureActive
                .stream()
                .filter(producer -> producer.getPod().equals(pod))
                .findFirst()
                .get();
producersProcedureActive.remove(p);

Is it possible to combine get and remove in a lambda expression?

是否可能在lambda表达式中合并get和remove ?

8 个解决方案

#1


17  

To Remove element from the list

从列表中删除元素。

objectA.removeIf(x -> conditions);

objectA。removeIf(x - >条件);

eg: objectA.removeIf(x -> blockedWorkerIds.contains(x));

objectA。removeIf(x - > blockedWorkerIds.contains(x));

List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");

List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");

str1.removeIf(x -> str2.contains(x)); 

str1.forEach(System.out::println);

OUTPUT: A B C

输出:A B C

#2


13  

Consider using vanilla java iterators to perform the task:

考虑使用vanilla java迭代器来执行任务:

public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
    T value = null;
    for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
        if (test.test(value = it.next())) {
            it.remove();
            return value;
        }
    return null;
}

Advantages:

优点:

  1. It is plain and obvious.
  2. 这是显而易见的。
  3. It traverses only once and only up to the matching element.
  4. 它只遍历一次,并且只遍历匹配元素。
  5. You can do it on any Iterable even without stream() support (at least those implementing remove() on their iterator).
  6. 即使没有流()支持,也可以在任何可迭代的环境中执行(至少是那些在迭代器上实现了remove()的环境))。

Disadvantages:

缺点:

  1. You cannot do it in place as a single expression (auxiliary method or variable required)
  2. 不能将其作为单个表达式(辅助方法或必需的变量)就地完成

As for the

至于

Is it possible to combine get and remove in a lambda expression?

是否可能在lambda表达式中合并get和remove ?

other answers clearly show that it is possible, but you should be aware of

其他答案清楚地表明这是可能的,但你应该意识到

  1. Search and removal may traverse the list twice
  2. 搜索和删除可以遍历列表两次
  3. ConcurrentModificationException may be thrown when removing element from the list being iterated
  4. 当从正在迭代的列表中删除元素时,可能会抛出ConcurrentModificationException

#3


8  

The direct solution would be to invoke ifPresent(consumer) on the Optional returned by findFirst(). This consumer will be invoked when the optional is not empty. The benefit also is that it won't throw an exception if the find operation returned an empty optional, like your current code would do; instead, nothing will happen.

直接的解决方案是在findFirst()返回的可选项上调用ifPresent(consumer)。当可选项不是空的时候,将调用该使用者。好处还在于,如果find操作返回一个可选的空值,它不会抛出异常,就像您当前的代码所做的那样;相反,什么都不会发生。

If you want to return the removed value, you can map the Optional to the result of calling remove:

如果要返回已删除的值,可以将可选项映射到调用remove的结果:

producersProcedureActive.stream()
                        .filter(producer -> producer.getPod().equals(pod))
                        .findFirst()
                        .map(p -> {
                            producersProcedureActive.remove(p);
                            return p;
                        });

But note that the remove(Object) operation will again traverse the list to find the element to remove. If you have a list with random access, like an ArrayList, it would be better to make a Stream over the indexes of the list and find the first index matching the predicate:

但是请注意,remove(Object)操作将再次遍历列表以查找要删除的元素。如果您有一个具有随机访问权限的列表,比如ArrayList,那么最好在列表的索引上创建一个流,并找到与谓词匹配的第一个索引:

IntStream.range(0, producersProcedureActive.size())
         .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
         .boxed()
         .findFirst()
         .map(i -> producersProcedureActive.remove((int) i));

With this solution, the remove(int) operation operates directly on the index.

使用这个解决方案,删除(int)操作直接操作索引。

#4


3  

I'm sure this will be an unpopular answer, but it works...

我相信这将是一个不受欢迎的答案,但它确实有效……

ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
            .stream()
            .filter(producer -> producer.getPod().equals(pod))
            .findFirst()
            .ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}

p[0] will either hold the found element or be null.

p[0]要么保存找到的元素,要么为null。

The "trick" here is circumventing the "effectively final" problem by using an array reference that is effectively final, but setting its first element.

这里的“诀窍”是通过使用一个实际上是最终的数组引用来绕过“有效的最终”问题,但是要设置它的第一个元素。

#5


2  

With Eclipse Collections you can use detectIndex along with remove(int) on any java.util.List.

使用Eclipse集合,您可以在任何java.util.List上使用detectIndex和remove(int)。

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

If you use the MutableList type from Eclipse Collections, you can call the detectIndex method directly on the list.

如果您使用来自Eclipse集合的MutableList类型,您可以直接在列表上调用detectIndex方法。

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

Note: I am a committer for Eclipse Collections

注意:我是Eclipse集合的提交者。

#6


2  

Although the thread is quite old, still thought to provide solution - using Java8.

尽管这个线程很旧,但是仍然认为可以使用Java8提供解决方案。

Make the use of removeIf function. Time complexity is O(n)

使用removeIf函数。时间复杂度是O(n)

producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));

API reference: removeIf docs

API参考:removeIf文档

Assumption: producersProcedureActive is a List

假设:生产者操作是一个列表

NOTE: With this approach you won't be able to get the hold of the deleted item.

注意:使用这种方法,您将无法获得已删除项的所有权。

#7


1  

As others have suggested, this might be a use case for loops and iterables. In my opinion, this is the simplest approach. If you want to modify the list in-place, it cannot be considered "real" functional programming anyway. But you could use Collectors.partitioningBy() in order to get a new list with elements which satisfy your condition, and a new list of those which don't. Of course with this approach, if you have multiple elements satisfying the condition, all of those will be in that list and not only the first.

正如其他人所指出的,这可能是循环和可迭代的用例。在我看来,这是最简单的方法。如果您想要对列表进行适当的修改,无论如何都不能将其视为“真正的”函数式编程。但是,您可以使用collections . partitioningby()获得一个包含满足条件的元素的新列表,以及不满足条件的新列表。当然,有了这种方法,如果有多个元素满足条件,那么所有的元素都将在这个列表中,而不仅仅是第一个。

#8


0  

Combining my initial idea and your answers I reached what seems to be the solution to my own question:

结合我最初的想法和你的回答,我找到了我自己问题的答案:

public ProducerDTO findAndRemove(String pod) {
    ProducerDTO p = null;
    try {
        p = IntStream.range(0, producersProcedureActive.size())
             .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
             .boxed()
             .findFirst()
             .map(i -> producersProcedureActive.remove((int)i))
             .get();
        logger.debug(p);
    } catch (NoSuchElementException e) {
        logger.error("No producer found with POD [" + pod + "]");
    }
    return p;
}

It lets remove the object using remove(int) that do not traverse again the list (as suggested by @Tunaki) and it lets return the removed object to the function caller.

它允许使用remove(int)删除对象,该对象不会再次遍历列表(如@Tunaki建议的那样),并允许将删除的对象返回给函数调用者。

I read your answers that suggest me to choose safe methods like ifPresent instead of get but I do not find a way to use them in this scenario.

我读了你的答案,建议我选择像ifPresent这样的安全方法,而不是get,但是我没有找到在这种情况下使用它们的方法。

Are there any important drawback in this kind of solution?

这种解决方案有什么重要的缺点吗?

Edit following @Holger advice

编辑后@Holger建议

This should be the function I needed

这应该是我需要的函数

public ProducerDTO findAndRemove(String pod) {
    return IntStream.range(0, producersProcedureActive.size())
            .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))      
            .boxed()                                                                
            .findFirst()
            .map(i -> producersProcedureActive.remove((int)i))
            .orElseGet(() -> {
                logger.error("No producer found with POD [" + pod + "]"); 
                return null; 
            });
}

#1


17  

To Remove element from the list

从列表中删除元素。

objectA.removeIf(x -> conditions);

objectA。removeIf(x - >条件);

eg: objectA.removeIf(x -> blockedWorkerIds.contains(x));

objectA。removeIf(x - > blockedWorkerIds.contains(x));

List<String> str1 = new ArrayList<String>();
str1.add("A");
str1.add("B");
str1.add("C");
str1.add("D");

List<String> str2 = new ArrayList<String>();
str2.add("D");
str2.add("E");

str1.removeIf(x -> str2.contains(x)); 

str1.forEach(System.out::println);

OUTPUT: A B C

输出:A B C

#2


13  

Consider using vanilla java iterators to perform the task:

考虑使用vanilla java迭代器来执行任务:

public static <T> T findAndRemoveFirst(Iterable<? extends T> collection, Predicate<? super T> test) {
    T value = null;
    for (Iterator<? extends T> it = collection.iterator(); it.hasNext();)
        if (test.test(value = it.next())) {
            it.remove();
            return value;
        }
    return null;
}

Advantages:

优点:

  1. It is plain and obvious.
  2. 这是显而易见的。
  3. It traverses only once and only up to the matching element.
  4. 它只遍历一次,并且只遍历匹配元素。
  5. You can do it on any Iterable even without stream() support (at least those implementing remove() on their iterator).
  6. 即使没有流()支持,也可以在任何可迭代的环境中执行(至少是那些在迭代器上实现了remove()的环境))。

Disadvantages:

缺点:

  1. You cannot do it in place as a single expression (auxiliary method or variable required)
  2. 不能将其作为单个表达式(辅助方法或必需的变量)就地完成

As for the

至于

Is it possible to combine get and remove in a lambda expression?

是否可能在lambda表达式中合并get和remove ?

other answers clearly show that it is possible, but you should be aware of

其他答案清楚地表明这是可能的,但你应该意识到

  1. Search and removal may traverse the list twice
  2. 搜索和删除可以遍历列表两次
  3. ConcurrentModificationException may be thrown when removing element from the list being iterated
  4. 当从正在迭代的列表中删除元素时,可能会抛出ConcurrentModificationException

#3


8  

The direct solution would be to invoke ifPresent(consumer) on the Optional returned by findFirst(). This consumer will be invoked when the optional is not empty. The benefit also is that it won't throw an exception if the find operation returned an empty optional, like your current code would do; instead, nothing will happen.

直接的解决方案是在findFirst()返回的可选项上调用ifPresent(consumer)。当可选项不是空的时候,将调用该使用者。好处还在于,如果find操作返回一个可选的空值,它不会抛出异常,就像您当前的代码所做的那样;相反,什么都不会发生。

If you want to return the removed value, you can map the Optional to the result of calling remove:

如果要返回已删除的值,可以将可选项映射到调用remove的结果:

producersProcedureActive.stream()
                        .filter(producer -> producer.getPod().equals(pod))
                        .findFirst()
                        .map(p -> {
                            producersProcedureActive.remove(p);
                            return p;
                        });

But note that the remove(Object) operation will again traverse the list to find the element to remove. If you have a list with random access, like an ArrayList, it would be better to make a Stream over the indexes of the list and find the first index matching the predicate:

但是请注意,remove(Object)操作将再次遍历列表以查找要删除的元素。如果您有一个具有随机访问权限的列表,比如ArrayList,那么最好在列表的索引上创建一个流,并找到与谓词匹配的第一个索引:

IntStream.range(0, producersProcedureActive.size())
         .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
         .boxed()
         .findFirst()
         .map(i -> producersProcedureActive.remove((int) i));

With this solution, the remove(int) operation operates directly on the index.

使用这个解决方案,删除(int)操作直接操作索引。

#4


3  

I'm sure this will be an unpopular answer, but it works...

我相信这将是一个不受欢迎的答案,但它确实有效……

ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
            .stream()
            .filter(producer -> producer.getPod().equals(pod))
            .findFirst()
            .ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}

p[0] will either hold the found element or be null.

p[0]要么保存找到的元素,要么为null。

The "trick" here is circumventing the "effectively final" problem by using an array reference that is effectively final, but setting its first element.

这里的“诀窍”是通过使用一个实际上是最终的数组引用来绕过“有效的最终”问题,但是要设置它的第一个元素。

#5


2  

With Eclipse Collections you can use detectIndex along with remove(int) on any java.util.List.

使用Eclipse集合,您可以在任何java.util.List上使用detectIndex和remove(int)。

List<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = Iterate.detectIndex(integers, i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

If you use the MutableList type from Eclipse Collections, you can call the detectIndex method directly on the list.

如果您使用来自Eclipse集合的MutableList类型,您可以直接在列表上调用detectIndex方法。

MutableList<Integer> integers = Lists.mutable.with(1, 2, 3, 4, 5);
int index = integers.detectIndex(i -> i > 2);
if (index > -1) {
    integers.remove(index);
}

Assert.assertEquals(Lists.mutable.with(1, 2, 4, 5), integers);

Note: I am a committer for Eclipse Collections

注意:我是Eclipse集合的提交者。

#6


2  

Although the thread is quite old, still thought to provide solution - using Java8.

尽管这个线程很旧,但是仍然认为可以使用Java8提供解决方案。

Make the use of removeIf function. Time complexity is O(n)

使用removeIf函数。时间复杂度是O(n)

producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));

API reference: removeIf docs

API参考:removeIf文档

Assumption: producersProcedureActive is a List

假设:生产者操作是一个列表

NOTE: With this approach you won't be able to get the hold of the deleted item.

注意:使用这种方法,您将无法获得已删除项的所有权。

#7


1  

As others have suggested, this might be a use case for loops and iterables. In my opinion, this is the simplest approach. If you want to modify the list in-place, it cannot be considered "real" functional programming anyway. But you could use Collectors.partitioningBy() in order to get a new list with elements which satisfy your condition, and a new list of those which don't. Of course with this approach, if you have multiple elements satisfying the condition, all of those will be in that list and not only the first.

正如其他人所指出的,这可能是循环和可迭代的用例。在我看来,这是最简单的方法。如果您想要对列表进行适当的修改,无论如何都不能将其视为“真正的”函数式编程。但是,您可以使用collections . partitioningby()获得一个包含满足条件的元素的新列表,以及不满足条件的新列表。当然,有了这种方法,如果有多个元素满足条件,那么所有的元素都将在这个列表中,而不仅仅是第一个。

#8


0  

Combining my initial idea and your answers I reached what seems to be the solution to my own question:

结合我最初的想法和你的回答,我找到了我自己问题的答案:

public ProducerDTO findAndRemove(String pod) {
    ProducerDTO p = null;
    try {
        p = IntStream.range(0, producersProcedureActive.size())
             .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
             .boxed()
             .findFirst()
             .map(i -> producersProcedureActive.remove((int)i))
             .get();
        logger.debug(p);
    } catch (NoSuchElementException e) {
        logger.error("No producer found with POD [" + pod + "]");
    }
    return p;
}

It lets remove the object using remove(int) that do not traverse again the list (as suggested by @Tunaki) and it lets return the removed object to the function caller.

它允许使用remove(int)删除对象,该对象不会再次遍历列表(如@Tunaki建议的那样),并允许将删除的对象返回给函数调用者。

I read your answers that suggest me to choose safe methods like ifPresent instead of get but I do not find a way to use them in this scenario.

我读了你的答案,建议我选择像ifPresent这样的安全方法,而不是get,但是我没有找到在这种情况下使用它们的方法。

Are there any important drawback in this kind of solution?

这种解决方案有什么重要的缺点吗?

Edit following @Holger advice

编辑后@Holger建议

This should be the function I needed

这应该是我需要的函数

public ProducerDTO findAndRemove(String pod) {
    return IntStream.range(0, producersProcedureActive.size())
            .filter(i -> producersProcedureActive.get(i).getPod().equals(pod))      
            .boxed()                                                                
            .findFirst()
            .map(i -> producersProcedureActive.remove((int)i))
            .orElseGet(() -> {
                logger.error("No producer found with POD [" + pod + "]"); 
                return null; 
            });
}