使用 Dart 有条件地返回 Map() 中的元素
Posted
技术标签:
【中文标题】使用 Dart 有条件地返回 Map() 中的元素【英文标题】:Conditionally return element in Map() with Dart 【发布时间】:2020-02-06 11:19:37 【问题描述】:假设我有一个可迭代对象(可能是映射(键)、列表、集合等),并希望使用 Map() 将其转换为另一个具有函数 f 的可迭代对象。但是,我希望 f 在转换后仅在满足条件时返回一个值。
List<int> a = [1,2,3,4,5,6];
List<int> b = a.map((e) => (e % 2 == 0) ? e * 10 : null);
assert(b == [20,40,60]);
然而,这会返回一个错误,与 mapEntry 中任何类似的等效项一样,例如:
Map<int, String> a = 1:a, 2:b, 3:c, 4:d, 5:e, 6:f;
Map<int, String> b = a.map((k,v) => (k % 2 == 0) ? MapEntry(k*10,v) : null);
assert(b.keys.toList<int>() == [20,40,60]);
当然,有一些方法可以通过在映射值之前或之后循环遍历它来过滤掉不需要的值,从而牺牲效率和简洁性来解决这个问题。如:
List<int> b = a.where((e) => e%2).map((e) => e * 10);
List<int> b = a.map((e) => e * 10).where((e) => e%2);
或者简单地使用 for...in 或 forEach() 手动循环并迭代 a
,同时有条件地将更改后的结果添加到 b
,但这在代码方面会很冗长,并且会缺少 map() 的优化用于专业操作。
如果这可能的话,请告诉我 - 微优化积累了巨大的收益恕我直言 :)。
非常感谢任何帮助!
【问题讨论】:
【参考方案1】:当然,有一些方法可以通过在映射值之前或之后循环遍历它以过滤掉不需要的值来牺牲效率和简洁性。
嗯,效率(如性能)不应该受到影响,因为您正在链接一个一个处理值的迭代器。所以在这里使用 where() 应该不是问题。
如果你想要一个更紧凑的解决方案,你可以这样做(这会为 a 中的每个元素创建一个临时的新 List,这会降低效率):
List<int> b = a.expand((e) => [if (e % 2 == 0) e * 10]).toList();
对于 Map 案例,我认为您能做的最好的事情就是使用 where。我想到了另一种解决方案,但结果却是一团糟:
Map<int, String> c = Map.fromEntries(a.entries.expand((e) => [if (e.key % 2 == 0) MapEntry(e.key * 10, e.value)]));
【讨论】:
【参考方案2】:对于 map
的情况,使用 Dart 的可空 collection
包的相对干净的解决方案可能如下所示:
import 'package:collection/collection.dart';
...
Map<int, String> a = 1: "a", 2: "b", 3: "c", 4: "d", 5: "e", 6: "f";
final b = Map.fromEntries(
a.entries.map((entry) =>
entry.key % 2 == 0 ? MapEntry(entry.key * 10, entry.value) : null)
.whereNotNull()
);
print(b.keys.toList()); // prints [20, 40, 60]
关键是whereNotNull()
过滤器。编译器有助于推断所有正确的类型,包括内部块的可选返回类型 (MapEntry?
)。
【讨论】:
whereNotNull() 方法不可用! 它是collection
包的一部分;因此我的回答中的导入声明。 api.flutter.dev/flutter/package-collection_collection/…以上是关于使用 Dart 有条件地返回 Map() 中的元素的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 map 函数有条件地使用 React 和 Firebase 渲染元素?