好的,这是我头脑中的一个概念验证,它已经困扰了我几天:
让我说我有:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
if (!str.equals("foo") || !str.equals("bar")) a.remove(str);
}
这会以列表[“foo”,“bazz”,“bar”]结束,因为它会读取索引1处的字符串(“buzz”),删除它,索引2处的字符串(“bazz”) )将跳转到索引1,它将在未经验证的情况下被绕过。
我想出的是:
List<String> a = new ArrayList<String>();
a.add("foo");
a.add("buzz");
a.add("bazz");
a.add("bar");
for (int i = 0; i < a.size(); i++)
{
String str = a.get(i);
boolean removed = false;
if (!str.equals("foo") || !str.equals("bar"))
{
a.remove(str);
removed = true;
}
if (removed) i--;
}
它应该以这种方式工作(至少它在我的头脑中大声笑),但是为迭代器搞乱并不是很好的做法。
其他方式我认为会创建一个“删除列表”并将项目添加到需要从列表a中删除的列表中,但这只会浪费资源。
那么,有效地从列表中删除项目的最佳做法是什么?
答案 0 :(得分:3)
使用Iterator
代替并使用Iterator#remove
方法:
for (Iterator<String> it = a.iterator(); it.hasNext(); ) {
String str = it.next();
if (!str.equals("foo") || !str.equals("bar")) {
it.remove();
}
}
从你的问题:
搞乱迭代器并不是一个好的做法
事实上,如果您code oriented to interfaces并直接使用List
代替ArrayList
,则使用get
方法可能会导航所有集合以获取所需元素(例如,如果您有一个List
支持单个链接列表)。因此,这里的最佳做法是使用迭代器而不是get
。
从列表中有效删除项目的最佳做法是什么?
不仅适用于List
,还适用于支持Iterable
的任何Collection
,并假设您没有索引或某种键(例如{ {1}})要直接访问元素,删除元素的最佳方法是使用Map
。
答案 1 :(得分:2)
您有三个主要选择:
使用Iterator
,因为它有方便的remove
方法。 : - )
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if (/*...you want to remove `it.next()`...*/) {
it.remove();
}
}
通过列表循环向后,这样如果删除某些内容,则下次迭代并不重要。这样做的好处是只需调用list.size()
一次。
for (int index = list.size() - 1; index >= 0; --index) {
// ...check and optionally remove here...
}
改为使用while
循环,只有在不删除该项时才会增加索引变量。
int index = 0;
while (index < list.size()) {
if (/*...you want to remove the item...*/) {
list.removeAt(index);
} else {
// Not removing, move to the next
++index;
}
}
请记住,除非您知道您正在处理ArrayList
,否则List#get(int)
的费用可能很高(可能是遍历)。但如果您知道您正在处理ArrayList
(或类似),那么......
答案 2 :(得分:1)
您的第一个示例可能会导致逐个错误,因为一旦删除对象,列表的索引就会发生变化。如果您想快速了解它,请使用iterator
或列表自己的.remove()
功能:
Iterator<String> itr = yourList.iterator();
while (itr.hasNext()) {
if ("foo".equals(itr.next()) {
itr.remove();
}
}
或者:
yourList.remove("foo");
yourList.removeAll("foo"); // removes all
答案 3 :(得分:1)
ArrayList.retainAll
有一个“智能”实现,它做正确的线性时间。您可以使用list.retainAll(Arrays.asList("foo", "bar"))
,然后您将在该行中获得快速实施。