【问题标题】:Cartesian product in Dart LanguageDart 语言中的笛卡尔积
【发布时间】:2019-09-02 09:25:53
【问题描述】:

如何在 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 语言没有。

【问题讨论】:

    标签: dart cartesian


    【解决方案1】:

    使用 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]]
    

    【讨论】:

    • 一个很棒的代码。这个怎么学的?我可以得到任何参考吗?
    • 我从其他语言的实现中学到了。谷歌有很多例子和答案。基本思路是一样的,尽量用递归调用来解决。
    【解决方案2】:

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

    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);
    }
    

    【讨论】:

    • 我认为这是专门针对两个列表而不是未知数量的列表。
    • 好点。 “列表的动态数量”使它变得更加复杂。
    • 是的,先生。这是我面临的主要问题。
    【解决方案3】:

    函数求解。

    //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 动态类型很傻,你可以使用类型友好的版本

    我不再使用 reduce 函数,因为它对参数和返回值有严格的维度限制

    友好输入

    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;
    }
    

    【讨论】:

    • 附言。 Dart 代码风格动态 lang,但它是静态的,随便省略了类型检查,这真的让我觉得很奇怪。
    【解决方案4】:

    试试这个解决方案:

    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));
    }
    

    【讨论】:

    • 我认为这是专门针对两个列表而不是未知数量的列表。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 2013-08-17
    • 2011-01-29
    • 2019-04-20
    • 2015-03-27
    相关资源
    最近更新 更多