我有
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};
然后我需要删除最后两个对象(a
和d
),因为它们已经在列表中了。
如何在不创建新列表的情况下完成这项工作?
答案 0 :(得分:5)
如果您致电list.Remove
,则会删除第一个实例;但是,您可以使用list.RemoveAt
和list.RemoveRange
。例如:
list.RemoveRange(5,2);
或更好:不要首先添加它们。
例如,如果您要从序列中添加,则可以在添加时使用Distinct
或HashSet<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
,它就会结束。如果它已经可用,它将从列表中删除。所以早起的鸟就会感染它。
但是,如果您想支持自定义类型,则需要在班级中覆盖Equals
和GetHashCode
,否则Contains
只会比较参考。
答案 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();
我当然更喜欢第二种解决方案,但它不能满足您的要求。