使用所有组合填充数组

时间:2014-05-08 14:00:51

标签: c# enums combinations

鉴于枚举,我想知道如何填充锯齿状数组,以便每个内部数组包含枚举值的组合(枚举中的7个值,内部数组中的6个插槽,允许重复)和外部数组包含每种可能的组合(不是排列;红色红色红色红色橙色和红色红色红色橙色红色是相同的元素)。

多维数组也可以工作,但是考虑到现实问题,锯齿状数组似乎更适用。我很难搞清楚填充它的循环是如何编写的。

语言是C#。我希望以一种方式对其进行填充,以便从最高"顺序对结果进行排序。至"最低"值,(从红色红色红色红色红色红色开始,然后是红色红色红色红色红色橙色等)。这是枚举:

public enum OrderedColors
{
    Colorless,
    Purple,
    Blue,
    Green,
    Yellow,
    Orange,
    Red
}

3 个答案:

答案 0 :(得分:0)

使用LINQ:

OrderedColors[] colors = (OrderedColors[])Enum.GetValues(typeof(OrderedColors));

OrderedColors[][] matrix = (
    from a in colors
    from b in colors
    from c in colors
    from d in colors
    from e in colors
    from f in colors
    select new [] {a,b,c,d,e,f}
).ToArray();

如果你想制作能够产生任何长度组合的东西,那么你需要更复杂的东西。

编辑:您可以通过在以下各项之后添加where子句来修复它:

OrderedColors[][] matrix = (
    from a in colors
    from b in colors
    where a<=b
    from c in colors
    where b<=c
    from d in colors
    where c<=d
    from e in colors
    where d<=e
    from f in colors
    where e<=f
    select new [] {a,b,c,d,e,f}
).ToArray();

答案 1 :(得分:0)

您可以使用简单的递归函数来实现它的可扩展性。它接收要组合的项目数组,要从数组中选择的项目数,以及从数组中选择seleft项目的起始索引(默认为0)。它会在每个允许的起始位置重新选择第一个项目,并将其他元素的所有组合附加到项目数组的右侧。

public static IEnumerable<T[]> BuildCombinations<T>(T[] items, int itemsCountInCombination, int startIndex = 0)
{
    if (itemsCountInCombination == 0)
    {
        yield return new T[0];
        yield break;
    }
    for (int i = startIndex; i < items.Length; i++)
    {
        foreach (var combination in BuildCombinations(items, itemsCountInCombination - 1, i))
        {
            var c = new T[itemsCountInCombination];
            c[0] = items[i];
            Array.Copy(combination, 0, c, 1, combination.Length);
            yield return c;
        }
    }
}


private static void Main(string[] args)
{
    foreach (var c in BuildCombinations(Enum.GetValues(typeof (OrderedColors)).Cast<OrderedColors>().Reverse().ToArray(), 6))
    {
        foreach (var color in c)
        {
            Console.Write(color);
            Console.Write(" ");
        }
        Console.WriteLine();
    }
}

它生成预期的924个组合,重复7个中的6个元素,在0.44ms内。它可能不是最好的性能,并且它使用的内存比可能的多,但它的实现非常简单,而且对于这么多元素来说足够高效。

答案 2 :(得分:0)

我发现这个问题很有意思,并继续致力于解决方案......在这里你去......

使用像这样的代码......

    var example = new[] { 
        OrderedColors.Red, OrderedColors.Orange, OrderedColors.Yellow, 
        OrderedColors.Green, OrderedColors.Blue, OrderedColors.Purple, 
        OrderedColors.Colorless };
    var combinations = example.CombinationsWithRepetition(6);

这会产生924个预期的结果,并且不会进行任何不必要的计算或复制。以下是实际方法。

    public static IEnumerable<IList<T>> CombinationsWithRepetition<T>
        (this IEnumerable<T> input, int take) where T : new()
    {
        var items = input.ToList();
        return CombinationsWithRepetition(items, null, take, 0, 0);
    }

    private static IEnumerable<IList<T>> CombinationsWithRepetition<T>
        (List<T> allItems, IList<T> thisSequence, int maxLength, 
        int currentLength, int currentIndex)
    {
        if (maxLength == 0)
            yield return new List<T>();
        for (var index = currentIndex; index < allItems.Count; index++)
        {
            var nextSequence = thisSequence == null ? new List<T>() : 
                  thisSequence.ToList();
            nextSequence.Add(allItems[index]);
            if (currentLength + 1 == maxLength)
            {
                yield return nextSequence;
            }
            else
            {
                foreach (var sequence in CombinationsWithRepetition(allItems, 
                   nextSequence, maxLength, currentLength + 1, index))
                {
                    yield return sequence;
                }
            }
        }
    }

享受!写它很有趣。