How to get all the unique n-long combinations of a set of duplicatable elements?

前端 未结 5 1920
难免孤独
难免孤独 2020-12-21 08:48

I have found many solutions giving a collection elements combined in all possible orders but they all use every element just once in every result while I need them to be tr

相关标签:
5条回答
  • 2020-12-21 08:51

    What you are asking for are permutations not combinations. Unique combinations can be found through tree traversal of k of n elements. If you want n of n elements unique, the answer is 1

    0 讨论(0)
  • 2020-12-21 08:56

    Simple - you count. If you have 3 elements, as in your example, and want all two-element combinations, you just count from 0 to 8 (3^2 - 1), and treat the result as a base-3 number with your elements as the digits.

    If you have 15 elements and want 8-element combinations, you count from 0 to 15^8-1 and treat your result as a base-15 number.

    0 讨论(0)
  • 2020-12-21 08:59

    You can use a depth first search:

    class Program
    {
        private static string[] letters = {"a", "b", "c"};
        private static void dfs(string accum, int depth)
        {
            if (depth == 0)
            {
                System.Console.WriteLine(accum);
                return;
            }
            foreach (string c in letters)
                dfs(accum + c, depth - 1);
        }
        public static void Main()
        {
            int depth = 2; //Number of letters in each result
            dfs("", depth);
            System.Console.ReadLine();
        }
    }
    


    Output:

    aa
    ab
    ac
    ba
    bb
    bc
    ca
    cb
    cc
    
    0 讨论(0)
  • 2020-12-21 09:07

    Lets say you've got N input elements, and you want a K-long combination.

    All you need to do is to count in base N, scoped of course, to all numbers that have K digits.

    So, lets say N = {n0, n1, ... nN}

    You'd start from the number [n0 n0 ... n0], and count all the way up to [nN nN ... nN]

    If you'd like help in understanding how to count in another base, you can get that here

    Each number that you compute maps to one of the K-long combinations that you need.

    I think an example will help

    I'll use your values. N = {a, b, c} So we want to count in base 3. Since we want 2-long combinations, we only care about 2-digit numbers. The smallest 2-digit base 3 number is 00, so we start there. By counting in base 3, we get:

    00
    01
    02
    10
    11
    12
    20
    21
    22
    

    Ok, so now to convert these numbers into a combination.

    Remember, our set is {a, b, c}

    So whenever we see a 0, it implies 1. Wherever we see 1, it implies 2, and I'm sure you can guess what a 2 implies :)

    00              aa
    01              ab
    02              ac
    10   0 => a     ba
    11   1 => b     bb
    12   2 => c     bc
    20              ca
    21              cb
    22              cc
    
    0 讨论(0)
  • 2020-12-21 09:12

    Eric Lippert has presented a general-purpose method of generating a cartesian product from any number of sequences which he blogs about here.

    He wrote an extension method that looks like this:

    public static class Combinations
    {
        public static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
        {
            IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
            return sequences.Aggregate(
                emptyProduct,
                (accumulator, sequence) =>
                from accseq in accumulator
                from item in sequence
                select accseq.Concat<T>(new[] { item }));
        }
    }
    

    Given that extension method, the solution to the original problem can be done like this:

    var items = new[] { "a", "b", "c" };
    
    int numInEachSelection = 2;
    
    var combs = Enumerable.Repeat(items, numInEachSelection).CartesianProduct();
    
    foreach (var comb in combs)
        Console.WriteLine(string.Join(", ", comb));
    

    Note that combs is an IEnumerable<IEnumerable<string>> - it is a sequence of enumerables each of which is a sequence representing one combination.

    If you don't need a general-purpose method like that and you are happy to have each combination in a separate object with properties called Item1 and Item2 for the two combined items, the easiest way is this:

    var items = new[] { "a", "b", "c" };
    
    var combs = from Item1 in items from Item2 in items select new {Item1, Item2};
    
    foreach (var comb in combs)
        Console.WriteLine(comb);
    
    0 讨论(0)
提交回复
热议问题