问题描述:

I have

 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};

Then I need to remove last two objects (a and d), because they already in the list.

How I can do it without creating new List?

网友答案:

If you call list.Remove it will remove the first instance; you can, however, use list.RemoveAt and list.RemoveRange. For example:

list.RemoveRange(5,2);

or better: don't add them in the first place.

For example, if you are adding from a sequence you can use Distinct or HashSet<T> to find unique items when adding.


After the fact, you could use:

    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);
        }
    }

To remove all but the first instance of duplicates.

Or perhaps more efficiently:

    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);
        }
    }
网友答案:

You could use this backwards for-loop and Enumerable.Contains + List.RemoveAt. This will not create a new list:

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);
}

So this loop gets one object via indexer, takes all objects before it's index and compares it with each other. Note that Take doesn't create a collection due to it's deferred execution, understood it as a loop, it'll end as soon as Contains returns true. If it's already available it will be removed from the list. So the early bird gets the worm.

However, if you want to support custom types you need to override Equals and GetHashCode in your class otherwise Contains will just compare the references.

Demo

网友答案:

How I can do it without creating new List?

You requirement is somewhat surprising (or at least you didn't explain why it is important that the list has to be modified in place), but here is a solution that favors speed of memory usage:

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;
}

Compare this to a solution where a new list is created:

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

I certainly prefer the second solution but it doesn't satisfy you requirement.

相关阅读:
Top