如何使用谓词从转换后的集合中删除元素?

发布于 2024-09-08 05:49:31 字数 377 浏览 2 评论 0原文

如果我有一个 ArrayListdblList 和一个 PredicateIS_EVEN 我可以使用以下方法从 dblList 中删除所有偶数元素:

Collections2.filter(dblList, IS_EVEN).clear()

if dblList 但是是转换的结果,这样

dblList = Lists.transform(intList, TO_DOUBLE)

的转换不再起作用列表是不可变的:-)

有什么解决方案吗?

If I have an ArrayList<Double> dblList and a Predicate<Double> IS_EVEN I am able to remove all even elements from dblList using:

Collections2.filter(dblList, IS_EVEN).clear()

if dblList however is a result of a transformation like

dblList = Lists.transform(intList, TO_DOUBLE)

this does not work any more as the transformed list is immutable :-)

Any solution?

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

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

发布评论

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

评论(6

单调的奢华 2024-09-15 05:49:31

Lists.transform() 接受一个 List 并返回一个结果 RandomAccess 列表。 Iterables.transform() 只接受 Iterable,结果不是 RandomAccess。最后, Iterables.removeIf (据我所知,这是 Iterables 中唯一的)有一个优化如果给定的参数是 RandomAccess,其要点是使算法线性而不是二次,例如,想象一下如果您有一个大 ArrayList(而不是 ArrayDeque - 应该更流行)并不断删除元素会发生什么从它的开始直到它为空。

但优化不依赖于迭代器remove(),而是依赖于 List.set(),在转换后的列表中不可能支持它。如果要解决这个问题,我们将需要另一个标记接口,以表示“可选的 set() 实际上有效”。

所以你的选择是:

  • 调用 Iterables.removeIf() 版本,并运行二次算法(如果你的列表很小或者删除的元素很少,这并不重要)
  • 将列表复制到另一个支持所有可选操作的列表中,< em>然后调用Iterables.removeIf()。

Lists.transform() accepts a List and helpfully returns a result that is RandomAccess list. Iterables.transform() only accepts an Iterable, and the result is not RandomAccess. Finally, Iterables.removeIf (and as far as I see, this is the only one in Iterables) has an optimization in case that the given argument is RandomAccess, the point of which is to make the algorithm linear instead of quadratic, e.g. think what would happen if you had a big ArrayList (and not an ArrayDeque - that should be more popular) and kept removing elements from its start till its empty.

But the optimization depends not on iterator remove(), but on List.set(), which is cannot be possibly supported in a transformed list. If this were to be fixed, we would need another marker interface, to denote that "the optional set() actually works".

So the options you have are:

  • Call Iterables.removeIf() version, and run a quadratic algorithm (it won't matter if your list is small or you remove few elements)
  • Copy the List into another List that supports all optional operations, then call Iterables.removeIf().
无人接听 2024-09-15 05:49:31

以下方法应该有效,尽管我还没有尝试过。

Collection<Double> dblCollection =
    Collections.checkedCollection(dblList, Double.class);
Collections2.filter(dblCollection, IS_EVEN).clear();

checkCollection() 方法生成未实现 List 的列表视图。 [创建一个 ForwardingCollection 会更简洁,但更冗长。] 然后 Collections2.filter() 将不会调用不受支持的 set() 方法。

库代码可以变得更加健壮。正如 Michael D 所建议的,当传递一个转换后的列表时,Iterables.removeIf() 可以生成一个组合谓词。然而,我们之前决定不通过添加此类特殊情况逻辑来使代码复杂化。

The following approach should work, though I haven't tried it yet.

Collection<Double> dblCollection =
    Collections.checkedCollection(dblList, Double.class);
Collections2.filter(dblCollection, IS_EVEN).clear();

The checkCollection() method generates a view of the list that doesn't implement List. [It would be cleaner, but more verbose, to create a ForwardingCollection instead.] Then Collections2.filter() won't call the unsupported set() method.

The library code could be made more robust. Iterables.removeIf() could generate a composed Predicate, as Michael D suggested, when passed a transformed list. However, we previously decided not to complicate the code by adding special-case logic of that sort.

甜嗑 2024-09-15 05:49:31

也许:

Collection<Double> odds = Collections2.filter(dblList, Predicates.not(IS_EVEN));

或者

dblList = Lists.newArrayList(Lists.transform(intList, TO_DOUBLE));
Collections2.filter(dblList, IS_EVEN).clear();

Maybe:

Collection<Double> odds = Collections2.filter(dblList, Predicates.not(IS_EVEN));

or

dblList = Lists.newArrayList(Lists.transform(intList, TO_DOUBLE));
Collections2.filter(dblList, IS_EVEN).clear();
九歌凝 2024-09-15 05:49:31

只要您不需要中间集合,那么您就可以使用 Predicates.compose() 创建一个谓词,该谓词首先转换项目,然后对转换后的项目计算谓词。

例如,假设我有一个 List我想从中删除整数部分为偶数的所有项目。我已经有一个 Function这给了我整数部分和谓词这告诉我它是否均匀。

我可以使用它们来获取新谓词 INTEGER_PART_IS_EVEN

Predicate<Double> INTEGER_PART_IS_EVEN = Predicates.compose(IS_EVEN, DOUBLE_TO_INTEGER);
Collections2.filter(dblList, INTEGER_PART_IS_EVEN).clear();

As long as you have no need for the intermediate collection, then you can just use Predicates.compose() to create a predicate that first transforms the item, then evaluates a predicate on the transformed item.

For example, suppose I have a List<Double> from which I want to remove all items where the Integer part is even. I already have a Function<Double,Integer> that gives me the Integer part, and a Predicate<Integer> that tells me if it is even.

I can use these to get a new predicate, INTEGER_PART_IS_EVEN

Predicate<Double> INTEGER_PART_IS_EVEN = Predicates.compose(IS_EVEN, DOUBLE_TO_INTEGER);
Collections2.filter(dblList, INTEGER_PART_IS_EVEN).clear();
恏ㄋ傷疤忘ㄋ疼 2024-09-15 05:49:31

经过一番尝试,我想我已经找到了:)

final ArrayList<Integer> ints = Lists.newArrayList(1, 2, 3, 4, 5);
Iterables.removeIf(Iterables.transform(ints, intoDouble()), even());
System.out.println(ints);

[1,3,5]

After some tries, I think I've found it :)

final ArrayList<Integer> ints = Lists.newArrayList(1, 2, 3, 4, 5);
Iterables.removeIf(Iterables.transform(ints, intoDouble()), even());
System.out.println(ints);

[1,3,5]
橘亓 2024-09-15 05:49:31

我没有解决方案,而是发现 Iterables.removeIf()Lists.TransformingRandomAccessList 结合使用时出现某种问题。

转换后的列表实现了 RandomAccess,因此 Iterables.removeIf() 委托给 Iterables.removeIfFromRandomAccessList(),它依赖于不受支持的 List.set() 操作。
不过,调用 Iterators.removeIf() 将会成功,因为 Lists.TransformingRandomAccessList 支持 remove() 操作。

请参阅:Iterables: 147

结论:instanceof RandomAccess 不能保证 List.set()。

添加:
在特殊情况下,调用removeIfFromRandomAccessList()甚至可以工作:
当且仅当要擦除的元素在列表尾部形成一个紧凑组或所有元素都被谓词覆盖时。

I don't have a solution, instead I found some kind of a problem with Iterables.removeIf() in combination with Lists.TransformingRandomAccessList.

The transformed list implements RandomAccess, thus Iterables.removeIf() delegates to Iterables.removeIfFromRandomAccessList() which depends on an unsupported List.set() operation.
Calling Iterators.removeIf() however would be successful, as the remove() operation IS supported by Lists.TransformingRandomAccessList.

see: Iterables: 147

Conclusion: instanceof RandomAccess does not guarantee List.set().

Addition:
In special situations calling removeIfFromRandomAccessList() even works:
if and only if the elements to erase form a compact group at the tail of the List or all elements are covered by the Predicate.

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