如何按从最少尝试到最多尝试的顺序获取一组 bool 组合?
How can I get an array of bool combinations in order from least trues to most trues?
我正在尝试创建一个布尔数组数组。我想要 bool 数组的所有组合,{false, false, false, false}
除外。我想要这个数组的顺序来保存它的子数组,这样它就按照从最不真实到最真实的顺序上升。 (倒序也可以,但还是得按顺序来。)
数组的每个子集都应随机排列。
我可以这样硬编码:
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 个布尔值。主数组具有子数组的所有组合,除了全部为 false。子数组应按 true 的数量排序,但每个具有一定数量 true 的部分应随机化。
如果这对我所追求的内容的解释不佳,我深表歉意……这有点难以解释。我可以澄清任何需要的东西。关于如何清理此硬编码版本的任何想法?
我假设您找到了一种方法来创建一个包含您需要的所有组合的数组。我们称它为 allCombinations
.
您可以使用以下命令创建有序数组:
bool[][] orderedCombinations = allCombinations.OrderBy(combination => combination.Count(b => b)).ToArray();
这按包含的 true
个值的数量对组合进行排序。具有相同数量 true
的组合未排序(但也未明确 randomized)。
希望这对您有所帮助。
UPDATE 要随机化具有相同数量 true
的组合,您可以试试这个:
Random rand = new Random();
bool[][] orderedCombinations = allCombinations.
OrderBy(combination => combination.Count(b => b)).
ThenBy(combination => rand.Next()).
ToArray();
让我们进行一系列小的重构。我们开始于:
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();
}
我们还注意到什么?我们说 "new bool[4]" 但编译器可以推断出类型和数字。
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();
}
这比原始代码好看多了。请注意我们如何简单地进行一系列清晰、正确的重构,使每个修订版都变得更好。
现在,你能做一个方法来获取你想要的 bool 总数和你想要的 true 数量吗?
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();
}
这就是我将要做的最简洁的内容。
注意这里的教训:
- 迭代的小变化可以导致大的结果。
- 将操作提取到专门用于这些操作的方法
- 使用编译器推理来减少冗余并提高可读性
- 使用表达式描述值的代码通常比使用语句描述操作的代码更紧凑。
- 拥抱抽象。请注意,当我们放弃将所有内容都塞入列表的愿望时,一切变得容易多了。
- 如果您要将事物实现为列表或数组,请尽可能晚地进行。
我正在尝试创建一个布尔数组数组。我想要 bool 数组的所有组合,{false, false, false, false}
除外。我想要这个数组的顺序来保存它的子数组,这样它就按照从最不真实到最真实的顺序上升。 (倒序也可以,但还是得按顺序来。)
数组的每个子集都应随机排列。
我可以这样硬编码:
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 个布尔值。主数组具有子数组的所有组合,除了全部为 false。子数组应按 true 的数量排序,但每个具有一定数量 true 的部分应随机化。
如果这对我所追求的内容的解释不佳,我深表歉意……这有点难以解释。我可以澄清任何需要的东西。关于如何清理此硬编码版本的任何想法?
我假设您找到了一种方法来创建一个包含您需要的所有组合的数组。我们称它为 allCombinations
.
您可以使用以下命令创建有序数组:
bool[][] orderedCombinations = allCombinations.OrderBy(combination => combination.Count(b => b)).ToArray();
这按包含的 true
个值的数量对组合进行排序。具有相同数量 true
的组合未排序(但也未明确 randomized)。
希望这对您有所帮助。
UPDATE 要随机化具有相同数量 true
的组合,您可以试试这个:
Random rand = new Random();
bool[][] orderedCombinations = allCombinations.
OrderBy(combination => combination.Count(b => b)).
ThenBy(combination => rand.Next()).
ToArray();
让我们进行一系列小的重构。我们开始于:
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();
}
我们还注意到什么?我们说 "new bool[4]" 但编译器可以推断出类型和数字。
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();
}
这比原始代码好看多了。请注意我们如何简单地进行一系列清晰、正确的重构,使每个修订版都变得更好。
现在,你能做一个方法来获取你想要的 bool 总数和你想要的 true 数量吗?
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();
}
这就是我将要做的最简洁的内容。
注意这里的教训:
- 迭代的小变化可以导致大的结果。
- 将操作提取到专门用于这些操作的方法
- 使用编译器推理来减少冗余并提高可读性
- 使用表达式描述值的代码通常比使用语句描述操作的代码更紧凑。
- 拥抱抽象。请注意,当我们放弃将所有内容都塞入列表的愿望时,一切变得容易多了。
- 如果您要将事物实现为列表或数组,请尽可能晚地进行。