Get all subsets of a collection

后端 未结 7 569
青春惊慌失措
青春惊慌失措 2021-01-13 17:05

I am trying to create a method that will return all subsets of a set.

For example if I have the collection 10,20,30 I will like to get the following ou

7条回答
  •  暖寄归人
    2021-01-13 17:24

    I know that this question is a little old but i was looking for a answer and dont find any good here, so i want to share this solution that is an adaptation found in this blog: http://praseedp.blogspot.com.br/2010/02/subset-generation-in-c.html

    I Only transform the class into a generic class:

    public class SubSet
    {
        private IList _list;
        private int _length;
        private int _max;
        private int _count;
    
        public SubSet(IList list)
        {
            if (list== null)
                throw new ArgumentNullException("lista");
            _list = list;
            _length = _list.Count;
            _count = 0;
            _max = (int)Math.Pow(2, _length);
        }
    
    
        public IList Next()
        {
            if (_count == _max)
            {
                return null;
            }
            uint rs = 0;
    
            IList l = new List();            
    
            while (rs < _length)
            {
                if ((_count & (1u << (int)rs)) > 0)
                {
                    l.Add(_list[(int)rs]);                    
                }
                rs++;
            }
            _count++;
            return l;            
        }
    }
    

    To use this code you can do like something that:

            List lst = new List();
    
            lst.AddRange(new string[] {"A", "B", "C" });
    
            SubSet subs = new SubSet(lst);
    
            IList l = subs.Next();
    
            while (l != null)
            {
    
                DoSomething(l);
                l = subs.Next();
            }
    

    Just remember: this code still be an O(2^n) and if you pass something like 20 elements in the list you will get 2^20= 1048576 subsets!

    Edit: As Servy sugest i add an implementation with interator block to use with Linq an foreach, the new class is like this:

    private class SubSet : IEnumerable>
        {
            private IList _list;
            private int _length;
            private int _max;
            private int _count;
    
            public SubSet(IEnumerable list)
            {
                if (list == null)
                    throw new ArgumentNullException("list");
                _list = new List(list);
                _length = _list.Count;
                _count = 0;
                _max = (int)Math.Pow(2, _length);
            }
    
            public int Count
            {
                get { return _max; }
            }
    
    
    
            private IList Next()
            {
                if (_count == _max)
                {
                    return null;
                }
                uint rs = 0;
    
                IList l = new List();
    
                while (rs < _length)
                {
                    if ((_count & (1u << (int)rs)) > 0)
                    {
                        l.Add(_list[(int)rs]);
                    }
                    rs++;
                }
                _count++;
                return l;
            }
    
            public IEnumerator> GetEnumerator()
            {
                IList subset;
                while ((subset = Next()) != null)
                {
                    yield return subset;
                }
            }
    
            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
        }
    

    and you now can use it like this:

            List lst = new List();
    
            lst.AddRange(new string[] {"A", "B", "C" });
    
            SubSet subs = new SubSet(lst);
    
            foreach(IList l in subs)
            {
                DoSomething(l);
            }
    

    Thanks Servy for the advice.

提交回复
热议问题