How to copy a List<T> without cloning
Asked Answered
F

1

7

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..

Foggy answered 28/7, 2012 at 22:25 Comment(3)
As far as I know, it's not possible 'out of the box'. Either you create your own collection type that will wrap the other collections (but it seems unnecessarily complicated), or more probably you'll want to rethink your program.Allegra
@KooKiz yes I get that. I can certainly live without it, but I was thinking a possibility..Foggy
It doesn't seem like it applies to your situation, but keep in mind it depends on what data type you're creating a list of. If it's List(of T as Class) then by default it will copy the reference and not clone the object. I think you will only run into the issue you're describing if you're working with a primitive type (or possible a struct).Barely
L
12

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?

Lurlenelurline answered 28/7, 2012 at 22:30 Comment(12)
@Foggy I'm curious. What if you want to add an item?Relive
@KendallFrey, I haven't thought about it. In fact my own question too was out of curiosity more than requirement. But yes, in case you add to smaller lists, I expect it to be added to unionlist. But if its added to unionlist, then the proper option is to neglect it in child lists. Mark's answer handles it this way, because public Add method is not defined :DFoggy
@MarkByers, more curiosity, how would it be if I have to add items to child lists? Is there a way it can be reflected in unionlist?Foggy
@nawfal: If you add an item to a child list, it will be available in the unioned list. But the problem is if you try to add an element directly to the unioned list. Which child list should it appear in, if any?Lurlenelurline
@MarkByers Leave the second part of the question, I admit its a conundrum impossible to determine, but I would suggest let it not be added to child lists. Which is the unionlist here in your code? List<List> is a list of lists, not list of all objects in each child list. So I do not think it meets my answer. I just had a second look now.Foggy
Normally, anything Added to a list is placed at the end of that list. In CombinedLists case I would assume that anything I added would also be added to the very end, which would mean it would end up being added to the very end of the very last combined list. Said another way, I would conceptually treat CombinedLists like I was dealing with the result of Enumerable.Concat for adding and insertions.Indenture
@MarkByers, new CombinedLists() gives list of lists right? That is different from list of all objects from each child list. Nevertheless cool thinking..Foggy
@nawfal: No. new CombinedLists() gives you what you want (once you have all the methods you need). Notice it implements IEnumerable<T>, not IEnumerable<List<T>>. I've added a couple more methods so you can compile the code and try it out for yourself.Lurlenelurline
Obviously there's really a lot missing before you can use this for anything useful. There's a lot of methods that List provides that I haven't implemented.Lurlenelurline
@MarkByers, I understand that. But it still eludes me how we get the combined list as expected. after all, all we do is add lists to list of lists. how is that we are getting list of all the objects from that class?? But its working :PFoggy
@nawfal: The key is SelectMany.Lurlenelurline
@MarkByers oh ok, now I get that enumerator part, one big thanks again (for patience) :DFoggy

© 2022 - 2024 — McMap. All rights reserved.