所有可能的现在给出排列的集合

时间:2014-09-03 05:38:00

标签: c# linq permutation

所以圣诞节即将到来,每年我的家人都会从帽子上取名,因为谁应该为谁买礼物,而且总是有顾虑,主要是配偶互相买礼物。

假设这些家庭是这样的:

List<List<string>> families = new List<List<string>> () 
{
    new List<string>() { "A1", "A2" }, 
    new List<string>() { "B1", "B2" }, 
    new List<string>() { "C1", "C2" }, 
    new List<string>() { "D1", "D2" }
};

A家庭的人不能为家庭中的其他人购买,同样适用于B,C,D家庭。

我们可以轻松地从一个特定的人那里得到一个家庭:

public static IEnumerable<string> FamilyOf(this List<List<string>> families, string person)
{
    return families.Where(family => family.Contains(person)).First();
}

...我们可以通过以下方式获得所有有效对:

var everyone = families.SelectMany(family => family);
var pairs = from giver in everyone
            from receiver in everyone
            where !families.FamilyOf(giver).Contains(receiver)
            select Tuple.Create(giver, receiver);

如何将此转换为包含所有人的有效赠送者/接收者的排列集合?从那以后我就选择一个随机集合。

1 个答案:

答案 0 :(得分:1)

我写了一些代码来解决你的问题,但它有时会引发异常,当它选择对时有点“不幸”。例如,如果算法对A1B2 B1C2 C1A2 - >因此只剩下D1和D2,这会导致异常,因为它不再符合您的配对要求。

无论如何,这里是代码,你可能想要扩展它以防止它抛出异常:

        var everyone = families.SelectMany(family => family).ToList();
        everyone.Shuffle();
        var randPairs = families.SelectMany(family => family)
            .Select(p => new { 
                Giver = p, 
                Receiver = everyone.PopRandom(x => !p.Contains(x[0])) 
            });

IList的两种扩展方法:

    public static T PopRandom<T>(this IList<T> list, Func<T, bool> predicate)
    {
        var predicatedList = list.Where(x => predicate(x));
        int count = predicatedList.Count();
        if (count == 0)
        {
            throw new Exception();
        }
        T item = predicatedList.ElementAt(Rand.Next(count));
        while (item != null && !predicate(item))
        {
            item = predicatedList.ElementAt(Rand.Next(list.Count));
        }
        list.Remove(item);

        return item;
    }

    public static void Shuffle<T>(this IList<T> list)
    {
        int n = list.Count;
        while (n > 1)
        {
            n--;
            int k = Rand.Next(n + 1);
            T value = list[k];
            list[k] = list[n];
            list[n] = value;
        }
    }