Iterable.expand(Iterable Function(dynamic) f) 函数在 Dart 中是如何工作的?
Posted
技术标签:
【中文标题】Iterable.expand(Iterable Function(dynamic) f) 函数在 Dart 中是如何工作的?【英文标题】:How does the Iterable.expand(Iterable Function(dynamic) f) function works in Dart? 【发布时间】:2021-09-25 18:20:15 【问题描述】:根据documentation 中的示例:
var pairs = [[1, 2], [3, 4]];
var flattened = pairs.expand((pair) => pair).toList();
print(flattened); // => [1, 2, 3, 4];
var input = [1, 2, 3];
var duplicated = input.expand((i) => [i, i]).toList();
print(duplicated); // => [1, 1, 2, 2, 3, 3]
如果它包含嵌套的可迭代对象,它看起来像是将可迭代对象展平,但问题是什么。
【问题讨论】:
"问题如何" ...这个问题不是很清楚。你想知道它的具体实现(即你想看它的代码),你想知道它的行为的具体细节(即它是否扁平化嵌套任意数量的迭代),或者你想知道你可能如何实现类似的东西? @jamesdlin 是的,我想知道它在幕后是如何运作的。 【参考方案1】:它的基本作用是,它在每次迭代时迭代调用参数函数的可迭代对象,并在迭代结束后连接参数函数返回的可迭代对象,最后返回作为可迭代对象的串联结果。
这是关于它如何工作的总结,让我们使用文档本身的示例来理解它:
var pairs = [[1, 2], [3, 4]];
var flattened = pairs.expand((pair) => pair).toList();
print(flattened); // => [1, 2, 3, 4];
这里我们有一个可迭代的pairs
,我们在上面调用了expand()
方法。现在expand()
方法将遍历pairs
,每次迭代调用一次参数函数(pair) => pair
。
注意expand()
方法的语法类似于Iterable<T> expand<T>(Iterable<T> f(T element))
,它清楚地表明它接受一个函数作为参数,该函数接受T
类型的参数并返回一个可迭代对象。例如(pair) => pair
其中pair
的类型为List<int>
到目前为止,我们很清楚 expand()
方法在每次迭代时迭代调用参数函数的可迭代对象。参数函数接受一个与可迭代对象类型相同的参数,并返回一个可迭代对象。
最后,expand()
方法连接参数函数返回的迭代,一旦迭代迭代,例如pairs
结束 [1, 2] + [3, 4] = [1, 2, 3, 4]
。然后它返回连接的结果,它是一个可迭代的[1, 2, 3, 4]
。
【讨论】:
【参考方案2】:它基本上只是一个循环中的一个循环,它遍历每个可迭代对象,找到内部可迭代对象的每个内部元素,然后将其作为单个展开的可迭代对象返回。
我找不到expand
的源代码,但是在我的darq 包中,您可以使用selectMany
方法看到相同的概念(这是因为selectMany
只是expand
与传递给选择器的附加索引)。至于 Dart 的 expand
是如何工作的,请忽略所有处理 index
的部分。
extension SelectManyExtension<T> on Iterable<T>
/// Maps elements in an iterable to collections and then flattens those
/// collections into a single iterable.
///
/// During iteration, the [selector] function is provided each value in the iterable
/// along with the index of the value in the iteration. The
/// returned collection of that function is then iterated over, and each
/// value in that iteration is provided as the next element of the
/// resulting iterable. The result is all of the collections flattened so that
/// their values become elements in a single iterable.
///
/// Example:
///
/// void main()
/// final list = ['abc', 'de', 'f', 'ghij'];
/// final result = list.selectMany((s, i) => s.iterable);
///
/// // Result: ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']
///
Iterable<TResult> selectMany<TResult>(
Iterable<TResult> Function(T element, int index) selector) sync*
var index = 0;
for (var v in this)
yield* selector(v, index++);
var list = [[1, 2, 3], [4, 5], [6]];
var flattened = list.selectMany((inner, idx) => inner);
// flattened = [1, 2, 3, 4, 5, 6]
【讨论】:
以上是关于Iterable.expand(Iterable Function(dynamic) f) 函数在 Dart 中是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章
chain(*iterable) 与 chain.from_iterable(iterable) 之间的区别
将 Iterable[Either[A,B]] 减少为 Either[A, Iterable[B]]