我怎样才能得到一系列bool组合,从最小的trues到大多数trues?

时间:2016-03-17 18:16:15

标签: c# arrays boolean combinations unity5

我正在尝试创建一个bool数组数组。我想拥有bool数组的每个组合,但{false, false, false, false}除外。我希望这个数组的顺序保持它的子数组,使它以最小的数量顺序上升到大多数真实状态。 (向后订单很好,但仍然必须订购。)

每个数组的子集应该具有相同数量的trues,应该是随机顺序。

我可以硬编码:

private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>();
    fourDoorList.Add(new bool[4] { true, true, true, true });
    fourDoorList = fourDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var threeDoorList = new List<bool[]>();
    threeDoorList.Add(new bool[4] { true, true, true, false });
    threeDoorList.Add(new bool[4] { true, true, false, true });
    threeDoorList.Add(new bool[4] { true, false, true, true });
    threeDoorList.Add(new bool[4] { false, true, true, true });
    threeDoorList = threeDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var twoDoorList = new List<bool[]>();
    twoDoorList.Add(new bool[4] { true, true, false, false });
    twoDoorList.Add(new bool[4] { true, false, true, false });
    twoDoorList.Add(new bool[4] { true, false, false, true });
    twoDoorList.Add(new bool[4] { false, true, true, false });
    twoDoorList.Add(new bool[4] { false, true, false, true });
    twoDoorList.Add(new bool[4] { false, false, true, true });
    twoDoorList = twoDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var oneDoorList = new List<bool[]>();
    oneDoorList.Add(new bool[4] { true, false, false, false });
    oneDoorList.Add(new bool[4] { false, true, false, false });
    oneDoorList.Add(new bool[4] { false, false, true, false });
    oneDoorList.Add(new bool[4] { false, false, false, true });
    oneDoorList = oneDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorList);
    boolArrayList.AddRange(threeDoorList);
    boolArrayList.AddRange(twoDoorList);
    boolArrayList.AddRange(oneDoorList);
    return boolArrayList.ToArray();
}

但那太脏了!

我可以创建一个这样的列表,但这些列表按我想要的方式排序:

private bool[][] GetBoolArrays()
{
    const int subArraySize = 4;
    bool[][] combinations = new bool[(int)Mathf.Pow(2, subArraySize) - 1][];
    for (int i = 1; i < Mathf.Pow(2, subArraySize); i++)
    {
        string binary = System.Convert.ToString(i, 2);
        while (binary.Length < subArraySize)
        {
            binary = 0 + binary;
        }
        bool[] singleCombination = binary.Select(c => c == '1').ToArray();
        combinations[i - 1] = singleCombination;
    }
    return combinations;
}

因此,为了澄清,我正在尝试创建一个数组数组。每个子阵列有4个bool。除了所有false之外,主数组具有子数组的每个组合。子阵列应按真实数量排序,但每个具有一定数量的真实性的部分应随机化。

如果这是对我所追求的不好解释,我道歉......这有点难以解释。我可以澄清任何需要的东西。关于如何清理硬编码版本的任何想法?

2 个答案:

答案 0 :(得分:11)

让我们进行一系列小型重构。我们从:

开始
private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>();
    fourDoorList.Add(new bool[4] { true, true, true, true });
    fourDoorList = fourDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var threeDoorList = new List<bool[]>();
    threeDoorList.Add(new bool[4] { true, true, true, false });
    threeDoorList.Add(new bool[4] { true, true, false, true });
    threeDoorList.Add(new bool[4] { true, false, true, true });
    threeDoorList.Add(new bool[4] { false, true, true, true });
    threeDoorList = threeDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var twoDoorList = new List<bool[]>();
    twoDoorList.Add(new bool[4] { true, true, false, false });
    twoDoorList.Add(new bool[4] { true, false, true, false });
    twoDoorList.Add(new bool[4] { true, false, false, true });
    twoDoorList.Add(new bool[4] { false, true, true, false });
    twoDoorList.Add(new bool[4] { false, true, false, true });
    twoDoorList.Add(new bool[4] { false, false, true, true });
    twoDoorList = twoDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var oneDoorList = new List<bool[]>();
    oneDoorList.Add(new bool[4] { true, false, false, false });
    oneDoorList.Add(new bool[4] { false, true, false, false });
    oneDoorList.Add(new bool[4] { false, false, true, false });
    oneDoorList.Add(new bool[4] { false, false, false, true });
    oneDoorList = oneDoorList.OrderBy(c => Random.Range(float.MinValue, float.MaxValue)).ToList();
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorList);
    boolArrayList.AddRange(threeDoorList);
    boolArrayList.AddRange(twoDoorList);
    boolArrayList.AddRange(oneDoorList);
    return boolArrayList.ToArray();
}

我们注意到的第一件事是重复的洗牌代码。将其解压缩到辅助扩展名。另外,为什么我们需要把它变成一个列表?我们稍后将把它传递给AddRange。将其保留为序列。

static IEnumerable<T> Shuffle<T>(this IEnumerable<T> items)
{
  return items.OrderBy(c => Random.Range(float.MinValue, float.MaxValue));
}

此外,我们现在有一个洗牌序列和一个未洗牌的列表。保持它们是单独的变量。

另外,我们注意到列表中没有任何内容,只有一件事在其中!

好的,现在我们得到了什么?

private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>();
    fourDoorList.Add(new bool[4] { true, true, true, true });
    var fourDoorListShuffle = fourDoorList; // No point shuffling!
    var threeDoorList = new List<bool[]>();
    threeDoorList.Add(new bool[4] { true, true, true, false });
    threeDoorList.Add(new bool[4] { true, true, false, true });
    threeDoorList.Add(new bool[4] { true, false, true, true });
    threeDoorList.Add(new bool[4] { false, true, true, true });
    var threeDoorListShuffle = threeDoorList.Shuffle();
    var twoDoorList = new List<bool[]>();
    twoDoorList.Add(new bool[4] { true, true, false, false });
    twoDoorList.Add(new bool[4] { true, false, true, false });
    twoDoorList.Add(new bool[4] { true, false, false, true });
    twoDoorList.Add(new bool[4] { false, true, true, false });
    twoDoorList.Add(new bool[4] { false, true, false, true });
    twoDoorList.Add(new bool[4] { false, false, true, true });
    var twoDoorListShuffle = twoDoorList.Shuffle();
    var oneDoorList = new List<bool[]>();
    oneDoorList.Add(new bool[4] { true, false, false, false });
    oneDoorList.Add(new bool[4] { false, true, false, false });
    oneDoorList.Add(new bool[4] { false, false, true, false });
    oneDoorList.Add(new bool[4] { false, false, false, true });
    var oneDoorListShuffle = oneDoorList.Shuffle();
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorListShuffle);
    boolArrayList.AddRange(threeDoorListShuffle);
    boolArrayList.AddRange(twoDoorListShuffle);
    boolArrayList.AddRange(oneDoorListShuffle);
    return boolArrayList.ToArray();
}

我们还注意到了什么?我们说&#34;新布尔[4]&#34;但编译器可以推断出类型和数字。

private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>();
    fourDoorList.Add(new[] { true, true, true, true });
    var fourDoorListShuffle = fourDoorList; // No point shuffling!
    var threeDoorList = new List<bool[]>();
    threeDoorList.Add(new[] { true, true, true, false });
    threeDoorList.Add(new[] { true, true, false, true });
    threeDoorList.Add(new[] { true, false, true, true });
    threeDoorList.Add(new[] { false, true, true, true });
    var threeDoorListShuffle = threeDoorList.Shuffle();
    var twoDoorList = new List<bool[]>();
    twoDoorList.Add(new[] { true, true, false, false });
    twoDoorList.Add(new[] { true, false, true, false });
    twoDoorList.Add(new[] { true, false, false, true });
    twoDoorList.Add(new[] { false, true, true, false });
    twoDoorList.Add(new[] { false, true, false, true });
    twoDoorList.Add(new[] { false, false, true, true });
    var twoDoorListShuffle = twoDoorList.Shuffle();
    var oneDoorList = new List<bool[]>();
    oneDoorList.Add(new[] { true, false, false, false });
    oneDoorList.Add(new[] { false, true, false, false });
    oneDoorList.Add(new[] { false, false, true, false });
    oneDoorList.Add(new[] { false, false, false, true });
    var oneDoorListShuffle = oneDoorList.Shuffle();
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorListShuffle);
    boolArrayList.AddRange(threeDoorListShuffle);
    boolArrayList.AddRange(twoDoorListShuffle);
    boolArrayList.AddRange(oneDoorListShuffle);
    return boolArrayList.ToArray();
}

更好。如果我们使用集合初始化程序而不是所有这些对Add的调用怎么办?

private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>() {
      new[] { true, true, true, true }};
    var fourDoorListShuffle = fourDoorList; // No point shuffling!
    var threeDoorList = new List<bool[]>() {
      new[] { true, true, true, false },
      new[] { true, true, false, true },
      new[] { true, false, true, true },
      new[] { false, true, true, true }};
    var threeDoorListShuffle = threeDoorList.Shuffle();
    var twoDoorList = new List<bool[]>() {
      new[] { true, true, false, false },
      new[] { true, false, true, false },
      new[] { true, false, false, true },
      new[] { false, true, true, false },
      new[] { false, true, false, true },
      new[] { false, false, true, true }};
    var twoDoorListShuffle = twoDoorList.Shuffle();
    var oneDoorList = new List<bool[]>() {
      new[] { true, false, false, false },
      new[] { false, true, false, false },
      new[] { false, false, true, false },
      new[] { false, false, false, true }};
    var oneDoorListShuffle = oneDoorList.Shuffle();
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorListShuffle);
    boolArrayList.AddRange(threeDoorListShuffle);
    boolArrayList.AddRange(twoDoorListShuffle);
    boolArrayList.AddRange(oneDoorListShuffle);
    return boolArrayList.ToArray();
}

更好。我们需要解释变量是什么?

private bool[][] GetBoolArrays()
{
    var fourDoorList = new List<bool[]>() {
      new[] { true, true, true, true }};
    var threeDoorList = new List<bool[]>() {
      new[] { true, true, true, false },
      new[] { true, true, false, true },
      new[] { true, false, true, true },
      new[] { false, true, true, true }};
    var twoDoorList = new List<bool[]>() {
      new[] { true, true, false, false },
      new[] { true, false, true, false },
      new[] { true, false, false, true },
      new[] { false, true, true, false },
      new[] { false, true, false, true },
      new[] { false, false, true, true }};
    var oneDoorList = new List<bool[]>() {
      new[] { true, false, false, false },
      new[] { false, true, false, false },
      new[] { false, false, true, false },
      new[] { false, false, false, true }};
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorList);
    boolArrayList.AddRange(threeDoorList.Shuffle());
    boolArrayList.AddRange(twoDoorList.Shuffle());
    boolArrayList.AddRange(oneDoorList.Shuffle());
    return boolArrayList.ToArray();
}

嗯,为什么中的任何必须是列表?

private bool[][] GetBoolArrays()
{
    var fourDoorList = new[] {
      new[] { true, true, true, true }};
    var threeDoorList = new[] {
      new[] { true, true, true, false },
      new[] { true, true, false, true },
      new[] { true, false, true, true },
      new[] { false, true, true, true }};
    var twoDoorList = new[] {
      new[] { true, true, false, false },
      new[] { true, false, true, false },
      new[] { true, false, false, true },
      new[] { false, true, true, false },
      new[] { false, true, false, true },
      new[] { false, false, true, true }};
    var oneDoorList = new[] {
      new[] { true, false, false, false },
      new[] { false, true, false, false },
      new[] { false, false, true, false },
      new[] { false, false, false, true }};
    var boolArrayList = new List<bool[]>();
    boolArrayList.AddRange(fourDoorList);
    boolArrayList.AddRange(threeDoorList.Shuffle());
    boolArrayList.AddRange(twoDoorList.Shuffle());
    boolArrayList.AddRange(oneDoorList.Shuffle());
    return boolArrayList.ToArray();
}

添加范围序列与连续序列相同:

private bool[][] GetBoolArrays()
{
    var fourDoorList = new[] {
      new[] { true, true, true, true }};
    var threeDoorList = new[] {
      new[] { true, true, true, false },
      new[] { true, true, false, true },
      new[] { true, false, true, true },
      new[] { false, true, true, true }};
    var twoDoorList = new[] {
      new[] { true, true, false, false },
      new[] { true, false, true, false },
      new[] { true, false, false, true },
      new[] { false, true, true, false },
      new[] { false, true, false, true },
      new[] { false, false, true, true }};
    var oneDoorList = new[] {
      new[] { true, false, false, false },
      new[] { false, true, false, false },
      new[] { false, false, true, false },
      new[] { false, false, false, true }};
    return fourDoorList.
      Concat(threeDoorList.Shuffle()).
      Concat(twoDoorList.Shuffle()).
      Concat(oneDoorList.Shuffle()).
      ToArray();
}

看起来比原始代码更好看。请注意我们如何简单地制作一系列清晰,正确的重构,使每个修订版更好一些。

现在,您是否可以制作一个方法来获取您想要的总数,以及您想要的数字?

static IEnumerable<bool[]> Combinations(int totalCount, int trueCount) 
{ 
    You implement this
}

假设我们有这样一种方法,这是一种练习。 (我博客上的组合文章可能有所帮助。)

现在我们可以写:

private bool[][] GetBoolArrays()
{
    var fourDoorList = Combinations(4, 4);
    var threeDoorList = Combinations(4, 3);
    var twoDoorList = Combinations(4, 2);
    var oneDoorList = Combinations(4, 1);
    return fourDoorList.
      Concat(threeDoorList.Shuffle()).
      Concat(twoDoorList.Shuffle()).
      Concat(oneDoorList.Shuffle()).
      ToArray();
}

现在,您可以编写一个具有此签名的方法:

static IEnumerable<T> MultiConcat(IEnumerable<IEnumerable<T>> sequences) 
{
   ... you implement this ...
}

如果可以,那么你可以写:

private bool[][] GetBoolArrays()
{
    var combinations = new[] {
      Combinations(4, 4).Shuffle(),
      Combinations(4, 3).Shuffle(),
      Combinations(4, 2).Shuffle(),
      Combinations(4, 1).Shuffle()};
    return combinations.MultiConcat().ToArray();
}

我认为这比原始代码更容易阅读。事实上,我们可以将其归结为一个声明:

private bool[][] GetBoolArrays()
{
    return new[] 
    {
      Combinations(4, 4).Shuffle(),
      Combinations(4, 3).Shuffle(),
      Combinations(4, 2).Shuffle(),
      Combinations(4, 1).Shuffle()
    }.MultiConcat().ToArray();
}

但现在我们可能会简洁。

但现在不要停止。那里有很多重复的代码!

private bool[][] GetBoolArrays()
{
  var q = from num in new[] { 4, 3, 2, 1 }
          select Combinations(4, num).Shuffle();
  return q.MultiConcat().ToArray();
}

哦等等,我们已经在LINQ中内置了一个多联接!嘿,很抱歉让你做这个练习,但我打赌它建立了性格。

private bool[][] GetBoolArrays()
{
  var q = from num in new[] { 4, 3, 2, 1 }
          select Combinations(4, num).Shuffle() into all
          from combinations in all
          from combination in combinations
          select combination;
  return q.ToArray();
}

这就像我要做到的那样简洁。

请注意这里的课程:

  • 迭代的小变化可以带来很大的成果。
  • 将操作提取到专门处理这些操作的方法
  • 使用编译器推断来减少冗余并提高可读性
  • 使用表达式描述值的代码通常比使用语句描述操作的代码更紧凑。
  • 拥抱抽象。请注意,当我们放弃将所有内容填入列表的愿望时,所有内容都变得容易多了。
  • 如果要将内容实现到列表或数组中,请尽可能在后期执行。

答案 1 :(得分:2)

我假设您找到了一种方法来创建一个包含所需组合的数组。我们称之为allCombinations

您可以使用以下方法创建有序数组:

bool[][] orderedCombinations = allCombinations.OrderBy(combination => combination.Count(b => b)).ToArray();

这会根据包含的true值的数量对组合进行排序。具有相同数量true s的组合未排序(但未明确随机化)。

希望这有帮助。

更新要对具有相同数量的true s的组合进行随机化,您可以尝试这样做:

Random rand = new Random();
bool[][] orderedCombinations = allCombinations.
    OrderBy(combination => combination.Count(b => b)).
    ThenBy(combination => rand.Next()).
    ToArray();