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