所以圣诞节即将到来,每年我的家人都会从帽子上取名,因为谁应该为谁买礼物,而且总是有顾虑,主要是配偶互相买礼物。
假设这些家庭是这样的:
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);
如何将此转换为包含所有人的有效赠送者/接收者的排列集合?从那以后我就选择一个随机集合。
答案 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;
}
}