2

I've researched and found LOTS of similar requests, but nothing was quite what I needed.

Here is my problem. I'm working in C#, and I have a FileInfo[] array with an unknown number of elements in it.

FileInfo[] files = new FileInfo[]
{
    new FileInfo(@"C:\a.jpg"),
    new FileInfo(@"C:\b.jpg"),
    new FileInfo(@"C:\c.jpg"),
    new FileInfo(@"C:\d.jpg"),
    new FileInfo(@"C:\e.jpg"),
    new FileInfo(@"C:\f.jpg"),
    new FileInfo(@"C:\g.jpg"),
    new FileInfo(@"C:\h.jpg"),
    new FileInfo(@"C:\i.jpg"),
}; // Using 9 elements for this example

And I need to generate a list of every possible reorder combination of these files, without repeating the files.

So, some of my results would be like this (example is not in code format):

a, b, c, d, e, f, g, h, i
a, b, c, d, e, f, g, i, h // i & h switched
a, b, c, d, e, f, h, g, i // last 3 elements switched

a, a, b, b, c, c, d, d, e // THIS IS NOT ACCEPTED, because elements are duplicated

And so on, until I've come up with every possible combination

So the total number of results should be the factorial of the number of elements in the array. In this example, there are 9 elements, so there should be 9*8*7*6*5*4*3*2*1=362,880 possible combinations.

I've been messing with this for a couple days now, and I just can't wrap my mind around it. Any help is appreciated, especially with code examples!

Thanks!

Robaticus
  • 22,857
  • 5
  • 54
  • 63
Jason Thuli
  • 736
  • 2
  • 8
  • 23
  • do you want to generate a list or test if an element is in that list? – Xodarap Sep 29 '10 at 19:37
  • 1
    Can you please clarify, why would you need it? There might be a better solution than generating 350000 FileInfo arrays, seriously. – Dan Abramov Sep 29 '10 at 19:45
  • @gaearon Hehehe, must be very true – Oskar Kjellin Sep 29 '10 at 19:47
  • I'm sure there is a MUCH better way. This was just my gameplan. After I submitted this current request for help, I decided to submit the big picture. It can be found here: http://stackoverflow.com/questions/3825387/c-code-to-fit-lots-of-files-onto-a-dvd-as-efficiently-as-possible – Jason Thuli Sep 29 '10 at 20:28

3 Answers3

5

Easy with Linq:

IEnumerable<FileInfo[]> permutations =
    from a in files
    from b in files.Except(new[] { a })
    from c in files.Except(new[] { a, b })
    from d in files.Except(new[] { a, b, c })
    from e in files.Except(new[] { a, b, c, d })
    from f in files.Except(new[] { a, b, c, d, e })
    from g in files.Except(new[] { a, b, c, d, e, f })
    from h in files.Except(new[] { a, b, c, d, e, f, g })
    from i in files.Except(new[] { a, b, c, d, e, f, g, h })
    select new[] { a, b, c, d, e, f, g, h, i };

EDIT:

Here's a generic solution, for any number of items:

static class ExtensionMethods
{
    public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> source, int count)
    {
        IEnumerable<IEnumerable<T>> result = new[] { Enumerable.Empty<T>() }; 
        for (int i = 0; i < count; i++)
        {
            result =  
                from seq in result 
                from item in source.Except(seq)
                select seq.Concat(new[] { item }); 
        } 
        return result;
    }
}

Use it as follows:

IEnumerable<IEnumerable<FileInfo>> permutations = files.GetPermutations(9);

(This solution is inspired by Eric Lippert's article about cartesian products.)


EDIT 2:

Here's a variant using Aggregate:

static class ExtensionMethods
{
    public static IEnumerable<IEnumerable<T>> GetPermutations2<T>(this IEnumerable<T> source, int count)
    {
        IEnumerable<IEnumerable<T>> seed = new[] { Enumerable.Empty<T>() }; 
        return Enumerable.Repeat(source, count)
            .Aggregate(
                seed,
                (accumulator, sequence) =>
                    from acc in accumulator
                    from item in sequence.Except(acc)
                    select acc.Concat(new[] { item }));
    }
}
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • But what if the number of items is unknown? – Oskar Kjellin Sep 29 '10 at 19:42
  • Yeah, I know... I'm working on it, but it will probably be a bit harder ;) – Thomas Levesque Sep 29 '10 at 19:44
  • Wow! Thanks for the fast reply! Linq looks very promising, I'll need to read up on it. But in the meantime, since I don't really understand the syntax of Linq, I'm not sure if you provided valid code or pseudocode, and it's erroring out on my system. Could you possibly provide a working example? Thanks! – Jason Thuli Sep 29 '10 at 19:52
  • @Jason, see the updated answer for a generic solution. What error are you getting ? You need to be using .NET 3.5 or higher or it won't work – Thomas Levesque Sep 29 '10 at 19:59
  • Thanks. I am using .NET 3.5. It's just a syntactical error. And not knowing the syntax of Linq, I figured I'd just ask. I'll try your generic solution. – Jason Thuli Sep 29 '10 at 20:04
  • Also, I submitted another request with a bigger picture to the project. Maybe I could get your ideas on it. http://stackoverflow.com/questions/3825387/c-code-to-fit-lots-of-files-onto-a-dvd-as-efficiently-as-possible – Jason Thuli Sep 29 '10 at 20:05
  • 2
    @Jason, this is not pseudocode, I ran it in LINQPad and it works fine. It returns the expected number of permutations, and the first ones seem to be correct (I didn't check all 362880 permutations of course...) – Thomas Levesque Sep 29 '10 at 20:08
  • I decided to go another way with the overall gameplan. Thanks for your help. I'm marking your solution as the correct one... basing it on faith ;-) – Jason Thuli Sep 29 '10 at 21:11
1

You really want all the Permutations of the set.

Edit: here is an example of exactly what you are talking about: http://www.codeproject.com/KB/recipes/Premutations.aspx

Alex Lo
  • 1,299
  • 8
  • 10
1

There are various algorithms available for doing this. The page below lists 3 different ones:

Counting And Listing All Permutations

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316