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 的 Iterable

英语iterable怎么翻译?

将 Iterable[Either[A,B]] 减少为 Either[A, Iterable[B]]

为啥 map over 一个 iterable 返回一个一次性的 iterable?

Python中参数iterable的意义