缺失的组合

时间:2015-01-19 23:12:46

标签: c#

所以我是C#的新手,我已经完成了这项任务:

我有一份身份不明的人员名单(例如5人)。任务是让列表中的人和他之后的人不在同一组中。

EX: 5个人

{1},{2},{3},{4},{5},{1,3},{1,4},{1,5},{2,4},{2, 5},{3,5},{1,3,5}

我使用了链接中的组合方法 http://www.codeproject.com/Articles/26050/Permutations-Combinations-and-Variations-using-C-G 我有这个代码

private void button3_Click(object sender, EventArgs e)
    {
        outputBox.Clear();
        int nr = Convert.ToInt32(nmbrBox.Value);
        double tmp = Math.Pow(2, nr);
        double combs = tmp - 1;
        List<int> list = new List<int>();
        for (int i = 1; i <= nr; i++ )
        {
            list.Add(i);
        }

        outputBox.AppendText(combs.ToString() + " combinari\n\n");

        List<string> allCombinations = new List<String>();
        for (int i = 1; i <= list.Count; i++)
        {
            var combis = new Facet.Combinatorics.Combinations<int>(list, i, Facet.Combinatorics.GenerateOption.WithoutRepetition);
            allCombinations.AddRange(combis.Select(c => string.Join("", c)));
        }

        foreach (var combi in allCombinations)
        {            
            outputBox.AppendText(combi + "\n");
        }
    }

我如何让它只显示我想要的结果?

2 个答案:

答案 0 :(得分:0)

我可以提供一个简单的解决方案。考虑到您的group字符串格式为“1 2 3”或“1”或“1 2”,allCombinations中的foreach组使用的验证方法如下:

public static bool IsGroupValid(string group)
{
    var indexes= group.Split(' ').Select(x=>Int32.Parse(x)).ToList();
    for (int i = 0; i < indexes.Count; i++)
    {
        if (indexes.Any(x=>x+1==indexes[i]))
            return false;
    }
    return true;
}

所以它看起来像那样:

foreach (var combi in allCombinations)
{        
    if(IsGroupValid(combi))    
        outputBox.AppendText(combi + "\n");
}

答案 1 :(得分:0)

您的问题是Windows窗体和一些组合代码的混合。在我的回答中,我将重点关注你问题的组合方面。您正在使用的库似乎非常好但是为了创建一个自包含的答案,我决定创建自己的方法来生成组合。实现是以一种不利于性能的方式使用LINQ和递归,但只要你没有太多不应该成为问题的元素。

要创建给定长度的源序列的组合,使用以下扩展方法(您必须将其放在static class内):

public static IEnumerable<IEnumerable<T>>  Combinations<T>(this IEnumerable<T> source, Int32 count)
  where T : IComparable<T> {
  if (count == 1)
    return source.Select(t => new T[] { t });
  return Combinations(source, count - 1)
    .SelectMany(
      values => source.Where(value => value.CompareTo(values.Last()) > 0),
      (values, value) => values.Concat(new T[] { value })
    );
}

如果输入为[1, 2, 3, 4, 5]count为4,则输出为[1, 2, 3, 4], [1, 2, 4, 5], [1, 3, 4, 5], [2, 3, 4, 5]

为了更容易确定组合是否有效,使用另一种扩展方法从序列创建元组:

public static IEnumerable<Tuple<T, T>> ToTuples<T>(this IEnumerable<T> source) {
  using (var enumerator = source.GetEnumerator()) {
    if (!enumerator.MoveNext())
      yield break;
    var lastValue = enumerator.Current;
    while (enumerator.MoveNext()) {
      yield return Tuple.Create(lastValue, enumerator.Current);
      lastValue = enumerator.Current;
    }
  }
} 

如果输入为[1, 2, 4, 5],则输出为[[1, 2], [2, 4], [4, 5]]

谓词用于确定给定的组合是否有效。假设该组合是一系列指数,因此两个连续的指数必须至少有2个部分才有效:

Boolean IsValidCombination(IEnumerable<Int32> combination) {
  return combination
    .ToTuples()
    .All(tuple => tuple.Item2 - tuple.Item1 > 1);
}

现在你可以把它放在一起。在这种情况下,输入是一个名称数组:

var people = new[] { "Arthur", "Bertha", "Cristobal", "Dolly", "Edouard" };
var indices = Enumerable.Range(0, people.Length);
var result = Enumerable
  .Range(1, people.Length - 1)
  .SelectMany(i => indices.Combinations(i))
  .Where(IsValidCombination)
  .Select(combination => combination.Select(i => people[i]));

这给出了以下结果:

Arthur
Bertha
Cristobal
Dolly
Edouard
Arthur, Cristobal
Arthur, Dolly
Arthur, Edouard
Bertha, Dolly
Bertha, Edouard
Cristobal, Edouard
Arthur, Cristobal, Edouard