删除List <t> </t>中的备用元素

时间:2009-03-07 13:05:28

标签: c# generics collections

在不使用占位符列表变量的情况下,删除List<T>中的备用(奇数索引或偶数索引)元素的最有效方法是什么?

如果您能提出每个答案的费用,我们将不胜感激。

我正在寻找一种高效方式来做到这一点

提前致谢

8 个答案:

答案 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());

}