我有一个 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/