How to get all subsets of an array?

前端 未结 12 2355
既然无缘
既然无缘 2020-11-27 17:54

Given an array: [dog, cat, mouse]

what is the most elegant way to create:

[,,]
[,,mouse]
[,cat,]
[,cat,mouse]
[dog,,]
[dog,,mouse]
[dog,         


        
相关标签:
12条回答
  • 2020-11-27 18:20

    Here's an easy-to-follow solution along the lines of your conception:

    private static void Test()
    {
        string[] test = new string[3] { "dog", "cat", "mouse" };
    
        foreach (var x in Subsets(test))
            Console.WriteLine("[{0}]", string.Join(",", x));
    }
    
    public static IEnumerable<T[]> Subsets<T>(T[] source)
    {
        int max = 1 << source.Length;
        for (int i = 0; i < max; i++)
        {
            T[] combination = new T[source.Length];
    
            for (int j = 0; j < source.Length; j++)
            {
                int tailIndex = source.Length - j - 1;
                combination[tailIndex] =
                    ((i & (1 << j)) != 0) ? source[tailIndex] : default(T);
            }
    
            yield return combination;
        }
    }
    
    0 讨论(0)
  • 2020-11-27 18:21

    You can use the BitArray class to easily access the bits in a number:

    string[] animals = { "Dog", "Cat", "Mouse" };
    List<string[]> result = new List<string[]>();
    int cnt = 1 << animals.Length;
    for (int i = 0; i < cnt; i++) {
       string[] item = new string[animals.Length];
       BitArray b = new BitArray(i);
       for (int j = 0; j < item.Length; j++) {
          item[j] = b[j] ? animals[j] : null;
       }
       result.Add(item);
    }
    
    0 讨论(0)
  • 2020-11-27 18:24
    static IEnumerable<IEnumerable<T>> GetSubsets<T>(IList<T> set)
    {
        var state = new BitArray(set.Count);
        do
            yield return Enumerable.Range(0, state.Count)
                                   .Select(i => state[i] ? set[i] : default(T));
        while (Increment(state));
    }
    
    static bool Increment(BitArray flags)
    {
        int x = flags.Count - 1; 
        while (x >= 0 && flags[x]) flags[x--] = false ;
        if (x >= 0) flags[x] = true;
        return x >= 0;
    }
    

    Usage:

    foreach(var strings in GetSubsets(new[] { "dog", "cat", "mouse" }))
        Console.WriteLine(string.Join(", ", strings.ToArray()));
    
    0 讨论(0)
  • 2020-11-27 18:24

    Here's a solution similar to David B's method, but perhaps more suitable if it's really a requirement that you get back sets with the original number of elements (even if empty):.

    static public List<List<T>> GetSubsets<T>(IEnumerable<T> originalList)
    {
        if (originalList.Count() == 0)
            return new List<List<T>>() { new List<T>() };
    
        var setsFound = new List<List<T>>();
        foreach (var list in GetSubsets(originalList.Skip(1)))
        {                
            setsFound.Add(originalList.Take(1).Concat(list).ToList());
            setsFound.Add(new List<T>() { default(T) }.Concat(list).ToList());
        }
        return setsFound;
    }
    

    If you pass in a list of three strings, you'll get back eight lists with three elements each (but some elements will be null).

    0 讨论(0)
  • 2020-11-27 18:25

    Guffa's answer had the basic functionality that I was searching, however the line with

    BitArray b = new BitArray(i);
    

    did not work for me, it gave an ArgumentOutOfRangeException. Here's my slightly adjusted and working code:

    string[] array = { "A", "B", "C","D" };
    int count = 1 << array.Length; // 2^n
    
    for (int i = 0; i < count; i++)
    {
        string[] items = new string[array.Length];
        BitArray b = new BitArray(BitConverter.GetBytes(i));
        for (int bit = 0; bit < array.Length; bit++) {
            items[bit] = b[bit] ? array[bit] : "";
        }
        Console.WriteLine(String.Join("",items));
    }
    
    0 讨论(0)
  • 2020-11-27 18:26

    I'm not very familiar with C# but I'm sure there's something like:

    // input: Array A
    foreach S in AllSubsetsOf1ToN(A.Length): 
        print (S.toArray().map(lambda x |> A[x]));
    

    Ok, I've been told the answer above won't work. If you value elegance over efficiency, I would try recursion, in my crappy pseudocode:

    Array_Of_Sets subsets(Array a) 
    {
        if (a.length == 0) 
             return [new Set();] // emptyset
        return subsets(a[1:]) + subsets(a[1:]) . map(lambda x |> x.add a[0]) 
    }
    
    0 讨论(0)
提交回复
热议问题