1

I was working on a class to find every combination of N lists. The combination algorithm seems to work flawlessly (when I step through it) but I am having trouble saving off my results. I want to store all the resulting arrays in another list to use later, but when I do the last array combination overwrites all the previous ones. Example input/outputs and my code are below. Does anyone have any ideas how I can fix this? (I've tried reference parameters and global lists with the same result).

/*
 Input: A B C
          X Y

  Expected Output: A X
                   A Y
                   B X
                   B Y
                   C X
                   C Y

  Actual Output:   C Y
                   C Y
                   C Y
                   C Y
                   C Y
                   C Y
*/


public class Combination<T>{
    private static void Combine(T[] res, int ix, List<List<T>> data, ref List<T[]> allCombos){
        foreach (T v in data[ix]){
            res[ix] = v;
            if (ix >= data.Count - 1){
                allCombos.Add(res);
            }else{
                Combine(res, ix + 1, data, ref allCombos);
            }
        }
    }

    public static List<T[]> Combine(List<List<T>> data){
        List<T[]> allCombos = new List<T[]>();
        Combine(new T[data.Count], 0, data, ref allCombos);
        return allCombos;
    }
}

4 Answers 4

3

The main problem here is that you only ever allocate a single T[] instance. Which you just add to your List<T[]> over and over.

Instead of this:

allCombos.Add(res);

You should try this:

allCombos.Add(res.ToArray());

That will create a new copy of the array each time as you add it to the list.

Sign up to request clarification or add additional context in comments.

Comments

0

try this. I think this should work. I am not on terminal to test it.

public class Combination<T>
{
    static T[] res;
    private static void Combine(int ix, List<List<T>> data, ref List<T[]> allCombos)
    {
        foreach (T v in data[ix])
        {
            res[ix] = v;
            if (ix >= data.Count - 1)
            {
                allCombos.Add(res);
            }
            else
            {
                Combine(res, ix + 1, data, ref allCombos);
            }
        }
    }

public static List<T[]> Combine(List<List<T>> data)
{
    List<T[]> allCombos = new List<T[]>();
    res = new  T[data.Count];
    Combine(0, data, ref allCombos);
    return allCombos;
}

}

Comments

0

The problem is that res argument is reused and overwritten in each iteration. Here is my solution for you.

using System;
using System.Linq;
using System.Collections.Generic;
....

    private IEnumerable<T[]> Combine<T>(IEnumerable<T[]> data)
    {
        if (!data.Any())
            yield break;

        var head = data.First();
        var tail = Combine(data.Skip(1));
        foreach (var e in head)
        {
            var list = new T[] {e};
            if (!tail.Any())
                yield return list;
            else
            {
                foreach (var t in tail)
                {
                    yield return list.Concat(t).ToArray();
                }
            }
        }
    }

Comments

0

For the record, I had a similar issue, with a list of custom objects recently. What did it for me was basically creating a new object, using the object that used to get overwriten ("subTree") as the basis.

//Do this
TreeView newTree= new TreeView { 
name = subTree.name,
children = subTree.children
};
actualTree.Add(newTree);
//Not this
actualTree.Add(subTree)

If I did not do that, I would have gotten the last "subTree" object everytime I tried to add a TreeView element to the "actualTree" List. The solution is to create a new object with the values that you need from other object whenever you have to add an element to your list, so that you are not always adding the same object.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.