如何有效地生成这些整数组合?

时间:2014-01-27 06:25:39

标签: c# algorithm combinations

我正在尝试生成这些组合:

1
2
3
4
5
12
13
14
15
23
24
25
34
35
45
123
124
125
134
135
145
234
245
345

这是我使用的代码之一,当然不起作用(在上面的例子中 maxValue 是5而 maxCount 是3):

bool nextCombination(int[] combination, int maxValue, int maxCount)
    {
        if (maxCount < 0)
        {
            return false;
        }
        else if (combination[maxCount] < maxValue)
        {
            combination[maxCount]++;
            return true;
        }
        else
        {
            return nextCombination(combination, maxValue - 1, maxCount - 1);
        }
    }

有人可以帮助我吗?

感谢。

1 个答案:

答案 0 :(得分:0)

您需要什么组合并不是很清楚。但是如果你想要这个最多3:

1
2
3
12
21
13
31
23
32
123
132
213
231
312
321

您将找到解决方案here

现在你已经添加了一个完整的例子,我知道你的意思。我添加了一些额外的方法来将上面的列表更改为您想要的内容。

这是您显示结果的方式:

public void ShowRequestedList()
{
    var lists = GetRequestedList(Enumerable.Range(1, 5), 3);
    foreach (var list in lists)
    {
        var text = String.Join("", list);
        Console.WriteLine(text);
    }
}

这是带有额外方法的博客的完整代码。首先是常规方法:

private IEnumerable<IEnumerable<T>> GetRequestedList<T>(IEnumerable<T> items, int maxLenght) where T : IComparable<T>
{
    // Next line is explained in the blog
    var lists = items.PermutationsWithMissingItems();

    // This is what you have to add
    return CombinationAreAscending(lists).Where(i => i.Count() <= maxLenght);
}

public IEnumerable<IEnumerable<T>> CombinationAreAscending<T>(IEnumerable<IEnumerable<T>> combinations) where T : IComparable<T>
{
    return combinations.Where(CombinationIsAscending);
}

private bool CombinationIsAscending<T>(IEnumerable<T> combination) where T : IComparable<T>
{
    var biggest = combination.First();
    foreach (var item in combination)
    {
        if (item.CompareTo(biggest) < 0)
        {
            return false;
        }
        biggest = item;
    }
    return true;
}

public static IEnumerable<int[]> GetCombinations(int length, int maxValue)
{
    return
        Enumerable.Range(1, maxValue - length)
            .Select(first => new { first, firstArray = new[] { first } })
            .SelectMany(@t => Enumerable.Range(@t.first + 1, maxValue - @t.first - 2),
                (@t, second) => @t.firstArray.Concat(Enumerable.Range(second, length)).ToArray());
}

然后使用扩展方法:

public static class Extensions
{
    public static IEnumerable<IEnumerable<T>> Permutations<T>(this IEnumerable<T> source)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        return source.PermutationsImplementation();
    }

    private static IEnumerable<IEnumerable<T>> PermutationsImplementation<T>(this IEnumerable<T> source)
    {
        var sourceCache = source.ToList(); // ToList() makes it about twice as fast
        if (sourceCache.IsSingle())
        {
            return sourceCache.ToIEnumerable();
        }
        return sourceCache
            .Select((a, index1) => PermutationsImplementation(sourceCache.Where((b, index2) => index2 != index1))
            .Select(b => a.PrependImplementation(b)))
            .SelectMany(c => c);
    }

    public static IEnumerable<TSource> Prepend<TSource>(
this TSource item,
IEnumerable<TSource> items)
    {
        if (items == null)
        {
            throw new ArgumentNullException("items");
        }
        return PrependImplementation(item, items);
    }

    private static IEnumerable<TSource> PrependImplementation<TSource>(
        this TSource item,
        IEnumerable<TSource> items)
    {
        yield return item;
        foreach (var item2 in items)
        {
            yield return item2;
        }
    }

    public static IEnumerable<TSource> ToIEnumerable<TSource>(this TSource item)
    {
        yield return item;
    }

    public static bool IsSingle<T>(this IEnumerable<T> source)
    {
        using (IEnumerator<T> enumerator = source.GetEnumerator())
        {
            return enumerator.MoveNext() && !enumerator.MoveNext();
        }
    }

    public static IEnumerable<IEnumerable<bool>> AllBooleansCombinations(int count)
    {
        if (count <= 0)
        {
            return Enumerable.Empty<IEnumerable<bool>>();
        }
        if (count == 1)
        {
            return OneBooleanCombination();
        }
        var result = AllBooleansCombinations(count - 1).Select(c => false.Prepend(c))
                        .Concat(
                        AllBooleansCombinations(count - 1).Select(c => true.Prepend(c)));
        return result;
    }

    private static IEnumerable<IEnumerable<bool>> OneBooleanCombination()
    {
        yield return false.ToIEnumerable();
        yield return true.ToIEnumerable();
    }

    public static IEnumerable<IEnumerable<T>> WithMissingItems<T>(this IEnumerable<T> source, bool orderItems = true)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        T[] sourceArray = source.ToArray();
        var booleansCombinations = AllBooleansCombinations(sourceArray.Length);
        var result = booleansCombinations.Select(b => FilterItems(b, sourceArray));
        if (orderItems)
        {
            result = result.Reverse().OrderBy(c => c.Count());
        }
        return result;
    }

    private static IEnumerable<T> FilterItems<T>(this IEnumerable<bool> booleans, T[] items)
    {
        var zippedCombinations = booleans.Zip(items, (boolean, item) => new { boolean, item });
        return zippedCombinations.Where(z => z.boolean).Select(z => z.item);
    }

    public static IEnumerable<IEnumerable<T>> PermutationsWithMissingItems<T>(
this IEnumerable<T> source)
    {
        if (source == null)
        {
            throw new ArgumentNullException("source");
        }
        var withMissingItems = source.WithMissingItems();
        return withMissingItems.SelectMany(m => m.Permutations());
    }
}