【问题标题】:Puzzled: I have 3 spaces (combination) and 3 categorical values. How do I compute all combinations of values?困惑:我有 3 个空格(组合)和 3 个分类值。如何计算值的所有组合?
【发布时间】:2022-01-14 10:31:51
【问题描述】:

这感觉应该比现在更容易,但如果我有价值观 A B C 我本来可以的

啊啊啊

A A B

e.t.c

A C B

C C A

e.t.c.

有没有一种简单的方法可以用 c#、javascript、python 或伪代码计算它们?我基本上想要一个二维数组,所有组合在一维中,值在另一维中。

【问题讨论】:

  • 这有点像在base2中计数
  • 以 2 为底数(尤其是以 3 为底数!)是一个很好的见解
  • 哈哈,这正是我的意思。不编辑我原来的评论,让全世界都知道我是个白痴!
  • 在python中你可以“作弊”,它已经在标准库中:from itertools import product 然后print(list(''.join(x) for x in product('ABC', repeat=3)))
  • 在伪代码中,对于少量元素,可以使用嵌套的for循环:for x0 in "ABC": for x1 in "ABC": for x2 in "ABC": print(x0,x1,x2)

标签: algorithm sorting


【解决方案1】:

所以对于那些想知道的人来说,这是一个粗略的解决方案吗? 这样做的目的是生成大小内核和类别组合的每个组合。

public static float[][] GenerateCombinations(int size, float[] categories)
    {
        List<float[]> combinations = new List<float[]>();
        var totalKernels = (int)Math.Pow(categories.Length, size);
        var currentIndexes = new int[size];

        var firstOutput = new float[size];
        combinations.Add(firstOutput);

        for (var i = 1; i < totalKernels; i++)
        {
            Console.Write("\n");
            var output = new float[size];
            var carry = 0;

            for (var j = 0; j < size; j++)
            {
                if (j == 0)
                {
                    currentIndexes[j]++;
                }
                if (carry != 0)
                {
                    currentIndexes[j] += carry;
                    carry = 0;
                }
                if (currentIndexes[j] >= categories.Length)
                {
                    carry = 1;
                    output[j] = categories[0];
                    currentIndexes[j] = 0;
                }
                else
                {
                    output[j] = categories[currentIndexes[j]];
                }
                Console.Write($" {output[j]}");
            }
            combinations.Add(output);
        }
        return combinations.ToArray();
    }

【讨论】:

  • 对你来说一个有趣的练习是在计数时更加字面化:编写一个名为 plusOne(string) 的函数,它推进最不重要的“数字” - 最右边的字符 - 并携带(仅硬部分)如有必要。那么您的解决方案就是“将 plusOne 呼叫至 CCC”。现在用完了,但我会在这里添加它——如果你还没有——当我回来时
  • 是的,我感觉这几乎是一个面试风格的问题。随意添加
  • 我不确定礼仪方面,谁是编辑的答案,所以我添加了一个非常字面的 base 3(小端)加法器解决方案。谢谢你的乐趣。 (我正在帮助一个朋友学习编码,我想我会向他提出这个问题)。
【解决方案2】:

您计算 N 位数的所有方式实际上都是在您计算 N-1 位数的所有方式之前的每个数字。你数一位数的所有方式,都是所有的数字。

这样...

function nCombosOfABC(nDigits) {
  if (nDigits === 1) return ['A', 'B', 'C']
  let result = []
  let n1 = nCombosOfABC(nDigits-1)
  for (let r of n1) {
    for (let letter of ['A', 'B', 'C']) {
      result.push([letter, ...r])
    }
  }
  return result
}

console.log(nCombosOfABC(3))

或者,作为 cmets 中的建议,更直接的添加(在 little-endian base 3 中)...

const addOne = string => {
    const adder = { A: { value: 'B' }, B: { value: 'C' }, C: { value: 'A', carry: true } }
    const digits = string.split('');
    const sum = adder[digits[0]];
    return sum.carry ? sum.value + addOne(digits.slice(1).join('')) : [sum.value, ...digits.slice(1)].join('')
}

for (let n = "AAA"; n != "CCC"; n = addOne(n)) {
    console.log(n)
}
console.log("CCC")

【讨论】:

  • 好答案。我喜欢在这里使用递归。我把事情复杂化了
  • 谢谢。在我编辑我的答案时,您一定已经发布了。它可能过于重视计数隐喻。
  • 是的,但它确实有效。不过更喜欢你的方式。干杯
【解决方案3】:

以下是python中的几种不同方法

三重嵌套循环

我们通过迭代第一个元素的所有可能值、迭代第二个元素的所有可能值以及迭代第三个元素的所有可能值来找到所有可能的三元组。

  • 优点:理解和编码极其简单;
  • 缺点:每个元组的元素数量是硬编码的;如果我们想要对、四胞胎或五胞胎而不是三胞胎,我们需要一个不同的函数。
def all_triplets(seq):
    for x in seq:
        for y in seq:
            for z in seq:
                yield (x,y,z)

print(list(all_triplets('AB')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'B', 'A'), ('B', 'B', 'B')]

print(list(all_triplets('ABC')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]

递归关系

我们使用笛卡尔积的递归关系代替嵌套循环:

product(seq with itself n times) == product(seq, product(seq with itself n-1 times))

我们仍然会迭代第一个元素的所有可能值;但是我们不会使用硬编码的嵌套循环来迭代剩余元素的所有可能值,而是使用递归关系来获取剩余元素的可能值。

像所有递归关系一样,它可以很容易地用于编写迭代函数或递归函数。由于python在递归方面非常糟糕,这里有一个迭代版本。

  • 优点:每个元组的元素数量现在是一个参数;
  • 缺点:这比硬编码的嵌套循环更难理解。
def all_n_uplets(seq, n):
    '''assume n >= 1'''
    result = seq
    for _ in range(n-1):
        result = [ (x, *t) for x in seq for t in result ]
    return result

print(all_n_uplets('ABC', 2))
# [('A', 'A'), ('A', 'B'), ('A', 'C'), ('B', 'A'), ('B', 'B'), ('B', 'C'), ('C', 'A'), ('C', 'B'), ('C', 'C')]

print(all_n_uplets('ABC', 3))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]

标准库

笛卡尔积已经在python中实现:it's function product in module itertools.它可以用来计算几个不同序列的笛卡尔积,或者一个序列与它自己的笛卡尔积。

  • 优点:它已经存在,无需重新实现轮子;
  • 缺点:名称 itertools.product 是特定于 python 的,如果您想使用其他语言,则需要寻找对应的名称。
from itertools import product

print(list(product('ABC', repeat=3)))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]

print(list(product('ABC', 'ABC', 'ABC')))
# [('A', 'A', 'A'), ('A', 'A', 'B'), ('A', 'A', 'C'), ('A', 'B', 'A'), ('A', 'B', 'B'), ('A', 'B', 'C'), ('A', 'C', 'A'), ('A', 'C', 'B'), ('A', 'C', 'C'), ('B', 'A', 'A'), ('B', 'A', 'B'), ('B', 'A', 'C'), ('B', 'B', 'A'), ('B', 'B', 'B'), ('B', 'B', 'C'), ('B', 'C', 'A'), ('B', 'C', 'B'), ('B', 'C', 'C'), ('C', 'A', 'A'), ('C', 'A', 'B'), ('C', 'A', 'C'), ('C', 'B', 'A'), ('C', 'B', 'B'), ('C', 'B', 'C'), ('C', 'C', 'A'), ('C', 'C', 'B'), ('C', 'C', 'C')]

请注意,搜索库函数会迫使您采用与社区使用的词汇一致的词汇。区分以下概念:

  • 笛卡尔积,或“替换组合”;
  • powerset,或“所有子集的集合”;
  • 排列;
  • 组合(无需替换);
  • 精神错乱;
  • 不同的排列(对于有重复的序列);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-19
    • 1970-01-01
    • 1970-01-01
    • 2021-02-01
    • 1970-01-01
    • 2021-09-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多