给定一个元素列表,我想获得具有给定属性和的元素从列表中删除它。我找到的最佳解决方案是:
ProducerDTO p = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.get();
producersProcedureActive.remove(p);
是否可以在lambda表达式中组合get和remove?
答案 0 :(得分:88)
要从列表中删除元素
objectA.removeIf(x - > conditions);
例如: 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);
<强>输出:强> 一个 乙 ç
答案 1 :(得分:24)
虽然线程很老,但仍然认为提供解决方案 - 使用Java8
。
使用removeIf
功能。时间复杂度为O(n)
producersProcedureActive.removeIf(producer -> producer.getPod().equals(pod));
API参考:removeIf docs
假设:producersProcedureActive
是List
注意:使用这种方法,您无法获得已删除项目的保留。
答案 2 :(得分:15)
考虑使用vanilla java迭代器来执行任务:
ACTION_VIEW
<强>优点强>:
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;
}
支持(至少在其迭代器上实现Iterable
),您也可以在任何stream()
上执行此操作。<强>缺点强>:
至于
是否可以在lambda表达式中组合get和remove?
其他答案清楚地表明这是可能的,但你应该知道
remove()
答案 3 :(得分:9)
直接解决方案是在ifPresent(consumer)
返回的Optional上调用findFirst()
。当optional不为空时,将调用此使用者。好处还在于,如果find操作返回一个空的可选项,它将不会抛出异常,就像您当前的代码一样;相反,什么都不会发生。
如果您想要返回已移除的值,可以map
Optional
调用remove
的结果:
producersProcedureActive.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.map(p -> {
producersProcedureActive.remove(p);
return p;
});
但请注意,remove(Object)
操作将再次遍历列表以查找要删除的元素。如果你有一个随机访问的列表,比如ArrayList
,那么最好在列表的索引上创建一个Stream,并找到与谓词匹配的第一个索引:
IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int) i));
使用此解决方案,remove(int)
操作直接在索引上运行。
答案 4 :(得分:5)
Use可以使用Java 8的过滤器,如果不想更改旧列表,则可以创建另一个列表:
List<ProducerDTO> result = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.collect(Collectors.toList());
答案 5 :(得分:3)
我确信这将是一个不受欢迎的答案,但它确实有效......
ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}
p[0]
将保留找到的元素或为null。
这里的“技巧”是通过使用数组引用来避开“有效最终”问题,该引用实际上是最终的,但设置了它的第一个元素。
答案 6 :(得分:2)
使用Eclipse Collections,您可以在任何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);
如果您使用Eclipse Collections中的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);
注意:我是Eclipse Collections的提交者
答案 7 :(得分:1)
正如其他人所建议的那样,这可能是循环和迭代的用例。在我看来,这是最简单的方法。如果您想要就地修改列表,则不能将其视为真实的&#34;无论如何功能编程。但是你可以使用Collectors.partitioningBy()
来获得一个包含满足你条件的元素的新列表,以及一个新的列表。当然,使用这种方法,如果您有多个元素满足条件,那么所有元素都将在该列表中,而不仅仅是第一个元素。
答案 8 :(得分:0)
结合我最初的想法和你的答案,我达到了似乎是解决方案 我自己的问题:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:id="@+id/imgMoviePoster"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_marginBottom="10dp"
android:scaleType="centerCrop"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ListView
android:id="@+id/lstMovies"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
它允许使用不再遍历的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;
}
删除对象
列表(由@Tunaki建议)和它允许将删除的对象返回到
函数调用者。
我看了你的答案,建议我选择remove(int)
而不是ifPresent
等安全方法,但我找不到在这种情况下使用它们的方法。
这种解决方案有什么重要的缺点吗?
编辑以下@Holger建议
这应该是我需要的功能
get
答案 9 :(得分:0)
以下逻辑是不修改原始列表的解决方案
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");
List<String> str3 = str1.stream()
.filter(item -> !str2.contains(item))
.collect(Collectors.toList());
str1 // ["A", "B", "C", "D"]
str2 // ["D", "E"]
str3 // ["A", "B", "C"]
答案 10 :(得分:0)
当我们想将列表中的多个元素放入新列表(使用谓词进行过滤)并将其从现有列表中删除时,我在任何地方都找不到合适的答案。
这是我们使用Java Streaming API分区的方法。
Map<Boolean, List<ProducerDTO>> classifiedElements = producersProcedureActive
.stream()
.collect(Collectors.partitioningBy(producer -> producer.getPod().equals(pod)));
// get two new lists
List<ProducerDTO> matching = classifiedElements.get(true);
List<ProducerDTO> nonMatching = classifiedElements.get(false);
// OR get non-matching elements to the existing list
producersProcedureActive = classifiedElements.get(false);
这样,您可以有效地从原始列表中删除过滤的元素,并将其添加到新列表中。
请参考 5.2。 this article的Collectors.partitioningBy 部分。
答案 11 :(得分:0)
任务是:获取✶和✶从列表中删除元素
p.stream().collect( Collectors.collectingAndThen( Collector.of(
ArrayDeque::new,
(a, producer) -> {
if( producer.getPod().equals( pod ) )
a.addLast( producer );
},
(a1, a2) -> {
return( a1 );
},
rslt -> rslt.pollFirst()
),
(e) -> {
if( e != null )
p.remove( e ); // remove
return( e ); // get
} ) );