arrays - 在 flutter 中更新卡住类中的深度嵌套数组

标签 arrays flutter dart immutability

我有一个 freezed flutter 类如下:

@freezed
abstract class Data with _$Data {
  const factory Data({
    String id,
    String name,
    String parentId,//null if it is the root element
    @Default([]) List<Data> children,
  }) = _Data;
}

该类包含一个名为 children 的属性。这是同一类的列表,即 Data .

当前允许的最大嵌套深度为 20 级。
我面临的问题是如何更新特定的深度嵌套 children通过向其中添加或删除项目来列出列表。此外,此更新应保持不变性并返回一个新的更新 Data类(class)。

我尝试使用 copyWith()卡住类上的方法,但在我的场景中嵌套很深时无法弄清楚。

最佳答案

我认为没有足够的信息来写一个准确的答案。但我将尝试展示如何做到这一点的想法。
这是代码:

/// recursive func to update children (should not be used directly, use `updateChildren` instead)
Data updateChildrenAt(Data data, List<Data> Function(List<Data>) update,
    List<int> indices, int depth) {
  final children = data.children;
  List<Data> newChildren;

  if (depth < indices.length) {
    final index = indices[depth];
    final child = children[index];
    newChildren = children.toList();
    newChildren[index] = updateChildrenAt(child, update, indices, depth + 1);
  } else {
    newChildren = update(children);
  }
  return data.copyWith(children: newChildren);
}

/// func to update children in the tree
Data updateChildren(
    Data data, List<Data> Function(List<Data>) update, List<int> indices) {
  return updateChildrenAt(data, update, indices, 0);
}
这是一个简单的递归函数(你应该知道,如果深度太深,它会失败并抛出异常,但像 20 这样的深度是可以的),它搜索子列表以通过提供的路径(索引)更新,因为我不确切知道你有什么信息,并决定编写某种通用算法(我希望,所以......)。
这是一个如何使用它的示例:
import 'data.dart';

/// func for demonstration
Data data(String name, [List<Data> children]) {
  return Data(name: name, children: children ?? []);
}

/// func for demonstration
String dataToStr(Data data, [int level = 0]) {
  var str = ' ' * level + data.name + ':\n';

  for (var i = 0; i < data.children.length; ++i) {
    str += dataToStr(data.children[i], level + 1);
  }

  return str;
}

/// func for demonstration
void printData(Data data) {
  print(dataToStr(data, 0));
}

void main(List<String> arguments) {
  final r = data('root', [
    data('level 1', [
      data('level 2_1', [
        data('level 3', [
          data('level 4', [
            data('level 5_1'),
            data('level 5_2',
                [data('level 6_1'), data('level 6_2'), data('level 6_3')]),
            data('level 5_3')
          ])
        ])
      ]),
      data('level_2_2'),
    ]),
  ]);

  // print initial value
  printData(r);
  // root:
  // level 1:
  //  level 2_1:
  //   level 3:
  //    level 4:
  //     level 5_1:
  //     level 5_2:
  //      level 6_1:
  //      level 6_2:
  //      level 6_3:
  //     level 5_3:
  //  level_2_2:

  // removing first element and adding new element at the end deep in the tree
  printData(updateChildren(r, (List<Data> children) {
    return children.sublist(1, children.length)..add(data('level 7 (added)'));
  }, [0, 0, 0, 0, 1]));
  // root:
  // level 1:
  //  level 2_1:
  //   level 3:
  //    level 4:
  //     level 5_1:
  //     level 5_2:
  //      level 6_2:
  //      level 6_3:
  //      level 7 (added):
  //     level 5_3:
  //  level_2_2:

  // adding new element in the start and in the end not very deep in the tree
  printData(updateChildren(r, (List<Data> children) {
    return [data('level 1_0 (added)'), ...children, data('level 1_2 (added)')];
  }, []));
  // root:
  // level 1_0 (added):
  // level 1:
  //  level 2_1:
  //   level 3:
  //    level 4:
  //     level 5_1:
  //     level 5_2:
  //      level 6_1:
  //      level 6_2:
  //      level 6_3:
  //     level 5_3:
  //  level_2_2:
  // level 1_2 (added):
}
你应该知道为了简单起见,所有检查都被省略了(我认为添加它们并不是很难,顺便说一句)。
更新:
这个例子中的索引是什么?
正如我所说,由于缺乏精确的信息(或者我可能还不够了解),我决定使用索引。
问题是在更新子列表之前,我们要找到该列表(我们要更新的列表)。我们无法仅通过有关深度的信息找到它,因为指定的数据表示树状数据结构。让我们看一个例子:
                        root
                          |
0                     [level 1 ]
                          |
1                    [level 2_1, level 2_2]
                          |          |
2                    [level 3]      [ ]
                          |
3                    [level 4]
                          |
4 [level 5_1,         level 5_2,             level 5_3]
       |                  |                      |
5     [ ]   [level 6_1, level 6_2, level 6_3]   [ ]
它是示例代码中根对象的表示(简化了,我希望我做对了......)。如果我们想要(如第一个示例)更新 [level 6_1, level 6_2, level 6_3] 的列表,关于深度的信息是不够的。因为在同一深度上有 3 个列表。我们到底要更新什么列表?这就是我添加索引的原因。数字 0-5 表示指定深度上所需的索引列表长度。此列表中的 index 表示我们想要在指定深度上更新的确切列表(因为,正如您在图像上看到的,每个深度都可以是任意数量的列表)。在第一个示例中,我们正在更新 [level 6_1, level 6_2, level 6_3] 列表。索引就像指定一个精确的路径一样。所以 [0, 0, 0, 0, 1] 意味着我们要更新 root.children[0].children[0].children[0].children[0].children[1].children 列表。例如,如果我们想要更新级别 2_2 下的空列表,我们应该能够使用索引:[0, 1]。在最后一个示例中,我们指定了一个空索引,这意味着我们要更新根子列表,即 [level 1] 列表。
因为你没有指定足够的信息,我不能说这是你真正想要的代码。也许你应该提供更多关于你想要完成的任务的信息。例如,也许您已经有一个要更新的列表,在这种情况下,如果不进行修改,上面的代码将无法运行。另一个示例,也许您想更新指定深度上的所有列表。在这种情况下,我们也需要更改代码。或者数据结构可能是错误的(例如),应该更改。我希望现在更清楚了。

关于arrays - 在 flutter 中更新卡住类中的深度嵌套数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62327350/

相关文章:

javascript - 如何隐藏多个元素

android - Flutter:在根项目 'assembleStageDebug' 中找不到任务 'android'

android - 如何在Dart中组合循环结果

dart - dart-HttpClientReques的编写正文失败?

dart - dart中有一个函数可以删除带有模式的子字符串吗?

c++ - C++ 中的 cout 没有打印出数组的值

php - 在 Codeigniter 中从多维数组检索数据

dart - 如何在 Flutter 中将 PointMode 传递给 Canvas.drawPoints(..)?

variables - 使用文本框输入获取值输出

javascript - 将 js Array() 转换为 JSON 对象以用于 JQuery .ajax