This is what I use:
Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
(xs == null || !xs.Any())
? Enumerable.Empty<IEnumerable<int>>()
: xs.Skip(1).Any()
? getAllSubsets(xs.Skip(1))
.SelectMany(ys => new[] { ys, xs.Take(1).Concat(ys) })
: new[] { Enumerable.Empty<int>(), xs.Take(1) };
Then you can do this:
var a = new [] { 50, 100, 120, 260, 360 };
Console.WriteLine(String.Join(", ", getAllSubsets(a).Select(x => x.Sum()).OrderBy(x => x)));
I get this:
0, 50, 100, 120, 150, 170, 220, 260, 270, 310, 360, 360, 380, 410,
410, 430, 460, 480, 480, 510, 530, 530, 580, 620, 630, 670, 720, 740,
770, 790, 840, 890
Knowing that values can be repeated then this is a way to go:
public IEnumerable<int> GenerateAllSums(int[] array)
{
var buffer = new LinkedList<int>();
buffer.AddFirst(0);
while (true)
{
var first = buffer.First;
var nexts = array.Select(a => first.Value + a);
foreach (var next in nexts)
{
var x = buffer.First;
while (x.Value < next)
{
x = x.Next;
if (x == null)
{
break;
}
}
if (x == null)
{
buffer.AddLast(next);
}
else if (x.Value != next)
{
buffer.AddBefore(x, next);
}
}
buffer.RemoveFirst();
yield return first.Value;
}
}
I can call it like so:
var a = new [] { 50, 100, 120, 260, 360, };
Console.WriteLine(String.Join(", ", GenerateAllSums(a).Take(100)));
It's important to note that the .Take(...)
is now vital as the sequence is infinite.
Given the .Take(100)
I get this result:
0, 50, 100, 120, 150, 170, 200, 220, 240, 250, 260, 270, 290, 300,
310, 320, 340, 350, 360, 370, 380, 390, 400, 410, 420, 430, 440, 450,
460, 470, 480, 490, 500, 510, 520, 530, 540, 550, 560, 570, 580, 590,
600, 610, 620, 630, 640, 650, 660, 670, 680, 690, 700, 710, 720, 730,
740, 750, 760, 770, 780, 790, 800, 810, 820, 830, 840, 850, 860, 870,
880, 890, 900, 910, 920, 930, 940, 950, 960, 970, 980, 990, 1000,
1010, 1020, 1030, 1040, 1050, 1060, 1070, 1080, 1090, 1100, 1110,
1120, 1130, 1140, 1150, 1160, 1170