Iterable.expand(Iterable Function(dynamic) f) 函数在 Dart 中如何工作?

How does the Iterable.expand(Iterable Function(dynamic) f) function works in Dart?

根据 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]

如果它包含嵌套的可迭代对象,它看起来像是压扁了一个可迭代对象,但问题是怎么回事。

它基本上只是一个循环中的一个循环,它迭代到每个可迭代对象,找到内部可迭代对象的每个内部元素,然后 returns 它作为一个单独的扩展可迭代对象。

我找不到 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]

它基本上做的是,它遍历可迭代对象,在每次迭代时调用参数函数,并在迭代结束后连接参数函数返回的可迭代对象,最后返回可迭代的连接结果.

这是对其工作原理的总结,让我们使用文档本身的示例来理解它:

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 和 returns 一个可迭代对象。例如 (pair) => pair 其中 pair 的类型是 List<int>

到目前为止,我们很清楚 expand() 方法在每次迭代时调用参数函数来迭代可迭代对象。参数函数接受一个与可迭代对象类型相同的参数,并且它 returns 是一个可迭代对象。

最后,expand() 方法在对可迭代对象进行迭代后将参数函数返回的可迭代对象连接起来,例如pairs结束[1, 2] + [3, 4] = [1, 2, 3, 4]。然后它 returns 连接的结果是一个可迭代的 [1, 2, 3, 4].