Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to copy a List<T> without cloning

Perhaps I am missing something trivial. I have a couple of List<T>s and I need one big list from them which is a union of all the other lists. But I do want their references in that big list and not just the values/copies (unlike many questions I typically find on SO).

For example I have this,

List<string> list1 = new List<string> { "a", "b", "c" };
List<string> list2 = new List<string> { "1", "2", "3" };

var unionList = GetThatList(list1, list2);

Suppose I get the list I want in unionList, then this should happen:

unionList.Remove("a"); => list1.Remove("a");
unionList.Remove("1"); => list2.Remove("1");

//in other words
//
//unionList.Count = 4;
//list1.Count = 2;
//list2.Count = 2;

To make it clear, this typically happens with

unionList = list1; //got the reference copy.

But how do I go about with the second list, list2 to add to unionList?

I tried Add and AddRange but they obviously clone and not copy.

unionList = list1;
unionList.AddRange(list2); //-- error, clones, not copies here.

and

foreach (var item in list2)
{
    unionList.Add(item); //-- error, clones, not copies here.
}

Update: I think I am asking something that makes no sense, and something that inherently is not possible in the language..

like image 744
nawfal Avatar asked Jul 28 '12 22:07

nawfal


1 Answers

I don't think any such class exists. You could implement it yourself. Here's a start:

class CombinedLists<T> : IEnumerable<T> // Add more interfaces here.
                                        // Maybe IList<T>, but how should it work?
{
    private List<List<T>> lists = new List<List<T>>();

    public void AddList(List<T> list)
    {
        lists.Add(list);
    }

    public IEnumerator<T> GetEnumerator()
    {
        return lists.SelectMany(x => x).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }

    public bool Remove(T t)
    {
        foreach (List<T> list in lists)
        {
            if (list.Remove(t)) { return true; }
        }
        return false;
    }

    // Implement the other methods.
}

Here's some code you can use to test it:

List<string> list1 = new List<string> { "a", "b", "c" };
List<string> list2 = new List<string> { "1", "2", "3" };
CombinedLists<string> c = new CombinedLists<string>();
c.AddList(list1);
c.AddList(list2);

c.Remove("a");
c.Remove("1");

foreach (var x in c) { Console.WriteLine(x); }
Console.WriteLine(list1.Count);
Console.WriteLine(list2.Count);

Removing items is fairly simple. But you might get problems if you try to insert items into your combined list. It is not always well-defined which list should receive the inserted items. For example, if you have a combined list that contains two empty lists and you insert an item at index 0, should the item be added to the first or the second empty list?

like image 79
Mark Byers Avatar answered Sep 23 '22 05:09

Mark Byers