当List包含相同的对象而不创建新列表</object>时,从List <object>中删除对象

时间:2013-05-17 06:45:19

标签: c# linq

我有

 var a = new object();
 var b = new object();
 var c = new object();
 var d = new object();
 var e = new object();
 var list = new List<object> {a, b, c, d, e, a, d};

然后我需要删除最后两个对象(ad),因为它们已经在列表中了。
如何在不创建新列表的情况下完成这项工作?

3 个答案:

答案 0 :(得分:5)

如果您致电list.Remove,则会删除第一个实例;但是,您可以使用list.RemoveAtlist.RemoveRange。例如:

list.RemoveRange(5,2);

或更好:不要首先添加它们

例如,如果您要从序列中添加,则可以在添加时使用DistinctHashSet<T>来查找唯一项目。


事实之后,您可以使用:

    var dups = from item in list
               group item by item into grp
               where grp.Count() > 1
               select grp.Key;

    foreach (var val in dups)
    {
        int first = list.IndexOf(val), last;
        while ((last = list.LastIndexOf(val)) != first)
        {
            list.RemoveAt(last);
        }
    }

删除所有重复项的第一个实例。

或者更有效率:

    for (int i = 0; i < list.Count; i++ )
    {
        var val = list[i];
        int first = list.IndexOf(val), last;
        while ((last = list.LastIndexOf(val)) != first)
        {
            list.RemoveAt(last);
        }
    }

答案 1 :(得分:3)

您可以使用此向前for循环和Enumerable.Contains + List.RemoveAt。这不会创建新列表:

var list = new List<object> { "a", "b", "c", "d", "e", "a", "d" };
for (int i = list.Count - 1; i >= 0; i--)
{
   var obj = list[i];
   if(list.Take(i).Contains(obj))
       list.RemoveAt(i);
}

所以这个循环通过索引器获取一个对象,在它的索引之前获取所有对象并将它们相互比较。请注意,Take不会因为延迟执行而创建集合,将其理解为循环,只要Contains返回true,它就会结束。如果它已经可用,它将从列表中删除。所以早起的鸟就会感染它。

但是,如果您想支持自定义类型,则需要在班级中覆盖EqualsGetHashCode,否则Contains只会比较参考。

Demo

答案 2 :(得分:-1)

  

如何在不创建新列表的情况下执行此操作?

您的要求有点令人惊讶(或者至少您没有解释为什么必须对列表进行修改很重要),但这是一个有利于内存使用速度的解决方案:

var set = new HashSet<object>();
var indicesToRemove = new List<int>();
for (var i = 0; i < list.Count; ++i) {
  var item = list[i];
  if (!set.Contains(item))
    set.Add(item);
  else
    indicesToRemove.Add(i);
}
var itemsRemovedSoFar = 0;
foreach (var i in indicesToRemove) {
  list.RemoveAt(i - itemsRemovedSoFar);
  itemsRemovedSoFar += 1;
}

将此与创建新列表的解决方案进行比较:

var list = list.Distinct().ToList();

我当然更喜欢第二种解决方案,但它不能满足您的要求。