How to get all subsets of an array?

前端 未结 12 2360
既然无缘
既然无缘 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:02

    Easy to understand version (with descriptions)

    I assumed that source = {1,2,3,4}

    public static IEnumerable<IEnumerable<T>> GetSubSets<T>(IEnumerable<T> source)
        {
            var result = new List<IEnumerable<T>>() { new List<T>() }; // empty cluster  added
    
            for (int i = 0; i < source.Count(); i++)
            {
                var elem = source.Skip(i).Take(1);
    
                // for elem = 2
                // and currently result = [ [],[1] ]
                var matchUps = result.Select(x => x.Concat(elem));
                //then matchUps => [ [2],[1,2] ]
    
                 result = result.Concat(matchUps).ToList();
                //  matchUps and result concat operation
                // finally result = [ [],[1],[2],[1,2] ]
            }
            return result;
        }
    
    0 讨论(0)
  • 2020-11-27 18:03
     string[] source = new string[] { "dog", "cat", "mouse" };
     for (int i = 0; i < Math.Pow(2, source.Length); i++)
     {
         string[] combination = new string[source.Length];
         for (int j = 0; j < source.Length; j++)
         {
             if ((i & (1 << (source.Length - j - 1))) != 0)
             {
                 combination[j] = source[j];
             }
        }
        Console.WriteLine("[{0}, {1}, {2}]", combination[0], combination[1], combination[2]);
    }
    
    0 讨论(0)
  • 2020-11-27 18:06

    Elegant? Why not Linq it.

        public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(IEnumerable<T> source)
        {
            if (!source.Any())
                return Enumerable.Repeat(Enumerable.Empty<T>(), 1);
    
            var element = source.Take(1);
    
            var haveNots = SubSetsOf(source.Skip(1));
            var haves = haveNots.Select(set => element.Concat(set));
    
            return haves.Concat(haveNots);
        }
    
    0 讨论(0)
  • 2020-11-27 18:08

    Here is a variant of mqp's answer, that uses as state a BigInteger instead of an int, to avoid overflow for collections containing more than 30 elements:

    using System.Numerics;
    
    public static IEnumerable<IEnumerable<T>> GetSubsets<T>(IList<T> source)
    {
        BigInteger combinations = BigInteger.One << source.Count;
        for (BigInteger i = 0; i < combinations; i++)
        {
            yield return Enumerable.Range(0, source.Count)
                .Select(j => (i & (BigInteger.One << j)) != 0 ? source[j] : default);
        }
    }
    
    0 讨论(0)
  • 2020-11-27 18:14

    The way this is written, it is more of a Product (Cartesian product) rather than a list of all subsets.

    You have three sets: (Empty,"dog"), (Empty,"cat"),(Empty,"mouse").

    There are several posts on general solutions for products. As noted though, since you really just have 2 choices for each axis a single bit can represent the presence or not of the item.

    So the total set of sets is all numbers from 0 to 2^N-1. If N < 31 an int will work.

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

    This is a small change to Mehrdad's solution above:

    static IEnumerable<T[]> GetSubsets<T>(T[] set) {
        bool[] state = new bool[set.Length+1];
        for (int x; !state[set.Length]; state[x] = true ) {
            yield return Enumerable.Range(0, state.Length)
                                   .Where(i => state[i])
                                   .Select(i => set[i])
                                   .ToArray();
            for (x = 0; state[x]; state[x++] = false);
        }
    }
    

    or with pointers

    static IEnumerable<T[]> GetSubsets<T>(T[] set) {
        bool[] state = new bool[set.Length+1];
        for (bool *x; !state[set.Length]; *x = true ) {
            yield return Enumerable.Range(0, state.Length)
                                   .Where(i => state[i])
                                   .Select(i => set[i])
                                   .ToArray();
            for (x = state; *x; *x++ = false);
        }
    }
    
    0 讨论(0)
提交回复
热议问题