Dart 语言中的笛卡尔积

Cartesian product in Dart Language

如何在 Dart 语言中创建动态列表数的笛卡尔积?

例如我有两个列表: X: [A, B, C]; Y: [W, X, Y, Z]

我想创建这样的列表[AW, AX, AY, AZ, BW, BX, BY, BZ, CW, CX, CY, CZ]

虽然 Python、Java 有预实现的库,但我认为 Dart 语言有 none。

试试这个解决方案:

void main() {
  List<String> a = ['A','B','C'];
  List<String> b = ['X','Y','Z'];
  List<String> c = a.map((ai) => b.map((bi) => ai+bi).toList()).expand((i) => i).toList();
  c.forEach((ci) => print(ci));
}

你可以把它写成一个简单的列表:

var product = [for (var x in X) for (var y in Y) "$x$y"];

(假设 XY 包含字符串,并且您想要的组合是连接,否则写其他东西而不是 "$x$y" 来组合 xy 值).

对于任意数量的列表,它会变得更加复杂。我可能更喜欢懒惰地生成组合,而不是在没有必要的情况下将所有列表同时保存在内存中。如果需要,您可以随时创建它们。

也许可以试试:

Iterable<List<T>> cartesian<T>(List<List<T>> inputs) sync* {
  if (inputs.isEmpty) { 
    yield List<T>(0);
    return;
  }
  var indices = List<int>.filled(inputs.length, 0);
  int cursor = inputs.length - 1;
  outer: do {
    yield [for (int i = 0; i < indices.length; i++) inputs[i][indices[i]]];
    do {
      int next = indices[cursor] += 1;
      if (next < inputs[cursor].length) {
        cursor = inputs.length - 1;
        break;
      }
      indices[cursor] = 0;
      cursor--;
      if (cursor < 0) break outer;
    } while (true);
  } while (true);
}

使用 Dart 2.5.0 测试:

class PermutationAlgorithmStrings {
  final List<List<String>> elements;

  PermutationAlgorithmStrings(this.elements);

  List<List<String>> permutations() {
    List<List<String>> perms = [];
    generatePermutations(elements, perms, 0, []);
    return perms;
  }

  void generatePermutations(List<List<String>> lists, List<List<String>> result, int depth, List<String> current) {
    if (depth == lists.length) {
      result.add(current);
      return;
    }

    for (int i = 0; i < lists[depth].length; i++) {
      generatePermutations(lists, result, depth + 1, [...current, lists[depth][i]]);
    }
  }
}

您可以输入任意长度的字符串数组。 像这样使用:

  PermutationAlgorithmStrings algo = PermutationAlgorithmStrings([
                      ["A", "B", "C"],
                      ["W", "X", "Y", "Z"],
                      ["M", "N"]
                    ]);

输出:

output: [[A, W, M], [A, W, N], [A, X, M], [A, X, N], [A, Y, M], [A, Y, N], [A, Z, M], [A, Z, N], [B, W, M], [B, W, N], [B, X, M], [B, X, N], [B, Y, M], [B, Y, N], [B, Z, M], [B, Z, N], [C, W, M], [C, W, N], [C, X, M], [C, X, N], [C, Y, M], [C, Y, N], [C, Z, M], [C, Z, N]]

函数式求解。

//declare type matters!
List<List<dynamic>> cards = [
    [1, 2, 3],
    [4, 5],
    ['x','y']
  ];

笛卡尔积

//or List flatten(List iterable) => iterable.expand((e) => e is List ? flatten(e) : [e]).toList(); // toList() cannot omit
Iterable flatten(Iterable iterable) => iterable.expand((e) => e is Iterable ? flatten(e) : [e]); 

//cannot omit  paramenter type 
List<List<dynamic>> cartesian(List<List<dynamic>> xs) =>
    xs.reduce((List<dynamic> acc_x, List<dynamic> x) =>  // type cannot be omit
        acc_x.expand((i) => x.map((j) => flatten([i, j]).toList())).toList());

也许使用 Dart 动态类型是愚蠢的,你可以使用类型友好的版本

I quit using reduce function because of its strict dimension limiting on parameters as well as returning values

类型友好

List<List<T>> cartesian<T>(List<List<T>> list) {
  var head = list[0];
  var tail = list.skip(1).toList();
  List<List<T>> remainder = tail.length > 0 ? cartesian([...tail]) : [[]];
  List<List<T>> rt = [];
  for (var h in head) {
    for (var r in remainder)
      rt.add([h, ...r]);
  }    
  return rt;
}