0

I have a sanctions api that i need to call, passing in a string of values. these values are constructed as follows:

string searchString = string.Join(" ", myList.ToArray());
// remove any numbers and return complete words
MatcCollection strMatch = Regex.Matches(searchString, @"[^\W\d]+");

var values = strMatch.Cast<Group>().Select(g => g.Value).ToArray();

var combinations = values.Permutations();

Now, that i have the array i need, i call the Permutations method below:

public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> source)
    {
        if (source == null)
            throw new ArgumentException("source");
        return permutations(source.ToArray());
    }

the permutations method is:

private static IEnumerable<IEnumerable<T>> permutations<T>(IEnumerable<T> source)
    {
        var c = source.Count();
        if (c == 1)
            yield return source;
        else
            for (int i = 0; i < c; i++)
                foreach (var p in permutations(source.Take(i).Concat(source.Skip(i + 1))))
                    yield return source.Skip(i).Take(1).Concat(p);
    }

With a example list of 7 items {one,two,three,four,five,six,seven} this code returns numerous list of 7 elements in lenght.

What I need to create is the following:

First iteration:

return result = one

Second iteration return result = one + ' ' + two

so on and so

I got the above exmple code from a post on SO, so don't know how to change it properly to get what i need.

CSharpNewBee
  • 1,951
  • 6
  • 28
  • 64

1 Answers1

2

So do I get right that not only you want all permutations of the 7 items, but also any subsets of them enumerated (something like all combinations)?

I guess the simplest way to get that behaviour would be adding some sort of length-parameter to the permutations method:

private static IEnumerable<IEnumerable<T>> permutations<T>(IEnumerable<T> source, int length)
{
    var c = source.Count();
    if (length == 1 || c == 1)
        foreach(var x in source)
            yield return new T[] { x };
    else
        for (int i = 0; i < c; i++)
            foreach (var p in permutations(source.Take(i).Concat(source.Skip(i + 1)), length - 1))
                yield return source.Skip(i).Take(1).Concat(p);
}

and then calling this method with parameters from 1 to n:

public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> source)
{
    if (source == null)
        throw new ArgumentException("source");
    var src = source.ToArray();
    for (int i = 1; i <= src.Length; i++)
        foreach (var result in permutations(src, i))
            yield return result;
}

Hope I didn't make any typos...

olydis
  • 3,192
  • 13
  • 28
  • the list olydis, could be any number, 7 was the example i'm running through at the moment. – CSharpNewBee Sep 12 '13 at 11:12
  • In my response I also just wanted to address that very example - my code does not expect it to be 7, does it? ;) – olydis Sep 12 '13 at 11:22
  • couple of errors with this Olydis: Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'System.Collections.Generic.IEnumerable>'. An explicit conversion exists (are you missing a cast?) and Cannot implicitly convert type 'System.Collections.Generic.IEnumerable' to 'T'. An explicit conversion exists (are you missing a cast?) – CSharpNewBee Sep 12 '13 at 11:22
  • ok that sorted that one, but still complains about yield return new T[] {source} – CSharpNewBee Sep 12 '13 at 11:27
  • ...because I was hopelessly stupid to use `source` instead of `x` - edited :) – olydis Sep 12 '13 at 11:31
  • 1
    Nice one. Is it possible to return a string for each item. it's currently an array. for example value = one value = one two value = one two three etc – CSharpNewBee Sep 12 '13 at 11:43
  • absolutely: i guess your source is of type `IEnumerable`, so the result of the method will be `IEnumerable>` ...then: `theresult.Select(x => string.Join(" ", x.ToArray()))` will return an `IEnumerable` with strings as I think you want them – olydis Sep 12 '13 at 11:47
  • i send in an array, and then for each combination of that array i'll need to break out of this loop and call the sanctions checking API, so i need just a string – CSharpNewBee Sep 12 '13 at 11:49
  • Sorry Olydid, whereabouts do i put the string.Join? – CSharpNewBee Sep 12 '13 at 12:48
  • exactly as shown in my snippet: `theresult.Select(x => string.Join(" ", x.ToArray()))` where `theresult` is the result of the call to `Permutations` – olydis Sep 12 '13 at 12:53
  • ...this snippet will return a collection of strings, formatted like "one two three" each – olydis Sep 12 '13 at 12:55