Java8Lambda从列表中获取并删除元素
给定一个元素列表,我想获取具有给定属性的元素,并将其从列表中删除。我找到的最佳解决方案是:Java8Lambda从列表中获取并删除元素,java,lambda,java-8,java-stream,Java,Lambda,Java 8,Java Stream,给定一个元素列表,我想获取具有给定属性的元素,并将其从列表中删除。我找到的最佳解决方案是: ProducerDTO p = producersProcedureActive .stream() .filter(producer -> producer.getPod().equals(pod)) .findFirst() .get(); producersProce
ProducerDTO p = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.get();
producersProcedureActive.remove(p);
是否可以在lambda表达式中组合get和remove?直接的解决方案是调用由返回的可选函数。当可选项不为空时,将调用此使用者。其好处还在于,如果find操作返回一个空的可选值,它不会抛出异常,就像您当前的代码一样;相反,什么也不会发生 如果要返回删除的值,可以将
可选映射到调用删除的结果:
producersProcedureActive.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.map(p -> {
producersProcedureActive.remove(p);
return p;
});
但请注意,该操作将再次遍历列表以查找要删除的元素。如果您有一个随机访问的列表,如ArrayList
,最好在列表的索引上创建一个流,并找到与谓词匹配的第一个索引:
IntStream.range(0, producersProcedureActive.size())
.filter(i -> producersProcedureActive.get(i).getPod().equals(pod))
.boxed()
.findFirst()
.map(i -> producersProcedureActive.remove((int) i));
使用此解决方案,操作将直接对索引进行操作。我确信这将是一个不受欢迎的答案,但它可以
ProducerDTO[] p = new ProducerDTO[1];
producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.findFirst()
.ifPresent(producer -> {producersProcedureActive.remove(producer); p[0] = producer;}
p[0]
将保留找到的元素或为空
这里的“诀窍”是通过使用一个实际上是final的数组引用来避免“effectivefinal”问题,但要设置它的第一个元素。考虑使用普通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;
}
public static T find和removefirst(Iterable),您可以在任何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集合的提交者正如其他人所建议的,这可能是循环和可重用的一个用例。在我看来,这是最简单的方法。如果您想修改列表,它无论如何都不能被认为是“真正的”函数编程。但是您可以使用收集器。partitioningBy()
为了得到一个包含满足您条件的元素的新列表,以及一个包含不满足您条件的元素的新列表。当然,通过这种方法,如果您有多个满足条件的元素,那么所有这些元素都将在该列表中,而不仅仅是第一个元素。结合我最初的想法和您的答案,我得出了一个似乎是解决方案的列表
对于我自己的问题:
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;
}
它允许使用不再遍历对象的remove(int)
删除对象
list(如@Tunaki所建议的)和允许将删除的对象返回到
函数调用者
我阅读了你的答案,其中建议我选择安全的方法,比如ifPresent
,而不是get
,但我没有找到在这种情况下使用它们的方法
这种解决方案有什么重要的缺点吗
编辑以下@Holger建议
这应该是我需要的功能
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;
});
}
从列表中删除元素
objectA.removeIf(x -> conditions);
例如:
objectA.removeIf(x->blockedWorkerIds.contains(x));
List str1=new ArrayList();
str1.添加(“A”);
str1.添加(“B”);
str1.添加(“C”);
str1.添加(“D”);
List str2=new ArrayList();
str2.添加(“D”);
str2.添加(“E”);
str1.removeIf(x->str2.contains(x));
str1.forEach(System.out::println);
输出:
A.
B
C虽然线程很旧,但仍然被认为可以提供解决方案-使用Java8
使用removeIf
函数。时间复杂度为O(n)
API参考:
假设:producerprocedureactive
是一个列表
注意:使用这种方法,您将无法保留已删除的项目。如果您不想更改旧列表,请使用Java 8的筛选器创建另一个列表:
List<ProducerDTO> result = producersProcedureActive
.stream()
.filter(producer -> producer.getPod().equals(pod))
.collect(Collectors.toList());
List result=producerproceductive
.stream()
.filter(producer->producer.getPod().equals(pod))
.collect(Collectors.toList());
以下逻辑是不修改原始列表的解决方案
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"]
List str1=new ArrayList();
str1.添加(“A”);
str1.添加(“B”);
str1.添加(“C”);
str1.添加(“D”);
List str2=new ArrayList();
str2.添加(“D”);
str2.添加(“E”);
列表str3=str1.stream()
.filter(项目->!str2.contains(项目))
.collect(Collectors.toList());
str1/[“A”、“B”、“C”、“D”]
str2/[“D”,“E”]
str3/[“A”、“B”、“C”]
当我们想从一个列表中获取多个元素到一个新列表中(使用谓词过滤)并将它们从现有列表中删除时,我在任何地方都找不到正确的答案
下面是我们如何使用Java流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);
Map classifiedElements=producerproceductive
.stream()
.collect(collector.partitionby(producer->producer.getPod().equals(pod));
//获取两个新列表
列表匹配=classifiedElements.get(true);
List nonMatching=classifiedElements.get(false);
//或者将不匹配的元素获取到现有列表
producerprocedureactive=classifiedElements.get(false);
通过这种方式,可以有效地从原始列表中删除过滤后的元素,并将其添加到新列表中
请参阅的5.2.Collectors.partitionby部分。任务是:获取✶和✶ 从列表中删除元素
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
} ) );
这对于链表来说是病态的。@chrylis索引解决方案确实是。根据列表实现的不同,一方会选择另一方。进行了一个小编辑。@chrylis:对于LinkedList
的情况,您可能不应该使用流API,因为没有不至少遍历两次的解决方案。但我不知道有什么解决方案在现实生活中,链表的学术优势可以补偿其实际开销。因此简单的解决方案是永远不要使用LinkedList
。哦,这么多编辑…现在第一个解决方案不提供删除的元素,因为remove(Object)
只返回一个boolean
告诉
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"]
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);
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
} ) );