So here's my implementation of a combine function. Note that while this is similar to permutations, it's slightly different in that I only take a certain subset in each pass (controlled by the count parameter). I'm hoping someone, perhaps one of the functional guys, can show me a more elegant way of doing this, but for now it works. I think the use of the HashSet in the Filter function provides a performance boost , but I don't know for certain. HashSet.Contains is an O(1) operation, but the cost of creating a new HashSet every iteration may cancel out that performance gain.
/// /// Filters the specified sequence based upon the provided indices.///
/// The type of the elements in the sequence.
/// The sequence.
/// The indices.
/// The filtered sequence.
public static IEnumerable Filter(this IEnumerable sequence, IEnumerable<int> indices)
{
HashSet<int> hs = indices as HashSet<int>;
if (hs == null)
hs = new HashSet<int>(indices);
return sequence.Where((t, i) => hs.Contains(i));
}
///
/// Generates all combinations (not permutations) of a given sequence.
///
/// The type of the elements in the sequence.
/// The sequence.
/// The number of items to pick for each combination.
/// The sequence of combinations.
public static IEnumerable> Combine(this IEnumerable sequence, int count)
{
List> results = new List>();
int[] indices = Enumerable.Range(0, count).ToArray();
int max = sequence.Count() - 1;
while (true)
{
results.Add(sequence.Filter(indices));
int n = count;
for (int i = indices.Length - 1; i >= 0; i--)
{
if (indices < max - (count - i - 1))
{
n = i;
break;
}
}
if (n == count)
break;
indices[n]++;
for (int i = n + 1; i < indices.Length; i++)
indices = indices + <span class="cpp-literal"><span class="cpp-number">1</span></span>;<br> }<br><br> <span class="cpp-keyword">return</span> results;<br>}<br></pre></div><!–ENDSCRIPT–><br><br>Well, maybe it's not all the interesting, but it does have that new LINQ-y, extension method smell, and it actually worked the first time I wrote it, so I'm happy.<div> </div>
Tentatively I'd think down two paths. One where the permutation of indices is contained within a lambda so when the linq predicate checks it, the lambda side-effects the permutation. The other is doing essentially a join in linq for all of the permutations/combinations and culling them via some criteria that I'm missing since I know of those words as synonyms...