在不使用占位符列表变量的情况下,删除List<T>
中的备用(奇数索引或偶数索引)元素的最有效方法是什么?
如果您能提出每个答案的费用,我们将不胜感激。
我正在寻找一种高效方式来做到这一点
提前致谢
答案 0 :(得分:27)
如果您为删除的每个项目调用RemoveAt,您将移动大量数据。最有效的方法是将要保留的项目移动到一起,然后删除最后未使用的项目:
int pos = 0;
for (int i = 0; i < values.Count; i += 2, pos++) {
values[pos] = values[i];
}
values.RemoveRange(pos, values.Count - pos);
编辑:
此方法将在15毫秒内处理一百万个整数的列表。使用RemoveAt将需要三分钟......
EDIT2:
实际上你可以从pos = 1和i = 2(或3)开始,因为第一项不必复制到自身。这使得代码不太明显。
答案 1 :(得分:8)
考虑到创建新列表的解决方案,使用列表 old ,您可以这样做:
var newList = old.Where((_, i) => i%2 != 0).ToList();
或者,显然
var newList = l.Where((_, i) => i%2 == 0).ToList();
取决于您选择的替换。
修改强>
答案要快得多。如果你在这里读到别的东西,那是因为我在一个周末和周末测量的大脑很有趣。 :( 封闭解决方案的速度提高约40%,而答案是应用程序。快2个数量级。我想这真的取决于你的名单有多大!
答案 2 :(得分:5)
另一个选项,类似于弗兰克的选项,但使用了闭包。它比弗兰克的版本更快。
bool isEven = true;
var newList = list.Where(x => isEven = !isEven).ToList();
答案 3 :(得分:2)
我不确定你的意思是替代,但如果你的意思是“其他所有项目”,以下代码将起作用。它将从删除第二个元素开始,然后是第四个元素,依此类推
List<T> list = GetTheList();
int i = 1;
while ( i < list.Count ) {
list.RemoveAt(i);
i++;
}
答案 4 :(得分:2)
Nirvana的方式是延期执行。或者其他什么。
public static IEnumerable<T> AlternateItems<T>(this IEnumerable<T> source)
{
while (source.Any())
{
yield return source.First();
source = source.Skip(1);
if (source.Any()) source = source.Skip(1);
}
}
这适用于所有序列,而不仅仅是IList<>
。迭代的成本推迟到迭代,如果最终你不需要触摸列表中的所有元素,这可能是一个很大的胜利。
在我的简单测试中,迭代整个列表时的性能不是很好,所以一定要描述一下你的实际情况。
答案 5 :(得分:1)
for (int i=myList.length-1; i >= 0; i--)
if (i % 2 == 0)
myList.Remove(myList[i]);
答案 6 :(得分:1)
显然使用依赖,但你可以有一个包装器IList,它将你给它的索引乘以2,并将列表的长度报告为1/2(细节省略)。这是O(1)。
答案 7 :(得分:0)
我会使用通常用于STL容器的标准模式。 删除后删除。
通过这种方式,您不会混淆习惯于看到此模式的人。
template<typename T>
struct RemoveEven
{
RemoveEven():count(0) {}
bool operator()(T const&)
{
bool result = count%2 == 0;
count++;
return result;
}
private:
std::size_t count;
};
int main()
{
std::list<int> a;
a.erase(std::remove_if(a.begin(),a.end(),RemoveEven<int>()),a.end());
}