For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/year/2027/proposal-joint-iteration.md.
  • 简体中文
  • Joint Iteration S4

    中文标题:联合迭代

    提案概览
    提案速览

    该提案通过添加 Iterator.zipIterator.zipKeyed 方法,解决了同步多个迭代器推进的需求,将多个可迭代对象中的对应值组合成数组或对象。它通过选项支持 "shortest"、"longest" 和 "strict" 等模式,并在 "longest" 模式下为较短的输入提供填充。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    联合迭代

    一个 TC39 提案,用于同步多个迭代器的推进,通常称为 zip

    阶段: 4。参见 tc39/ecma262#3802 的集成 PR。

    演示: https://tc39.es/proposal-joint-iteration/demo/

    规范: https://tc39.es/proposal-joint-iteration/

    动机

    通常你有两个或更多的迭代器,它们位置对齐(第一个迭代器产生的第一个值与另一个迭代器产生的第一个值对应,依此类推),并且你希望同时操作对应的值。一种常见的解决方案是 zip,它产生一个组合值的迭代器。zipWith 允许以元组之外的方式组合值。某些语言将 zipWith 表示为可变参数的 map

    向委员会做的展示

    提案

    该提案添加两个方法:Iterator.zipIterator.zipKeyedzip 接受一个可迭代对象的可迭代对象,并产生一个数组的可迭代对象,其中位置对应于传入可迭代对象中的位置。zipKeyed 接受一个对象,其值是可迭代对象,并产生一个对象的可迭代对象,其中键对应于传入对象中的键。

    Iterator.zip([
      [0, 1, 2],
      [3, 4, 5],
    ]).toArray()
    
    /*
    产生:
    [
      [0, 3],
      [1, 4],
      [2, 5],
    ]
    */
    
    Iterator.zipKeyed({
      a: [0, 1, 2],
      b: [3, 4, 5, 6],
      c: [7, 8, 9],
    }).toArray()
    
    /*
    产生:
    [
      { a: 0, b: 3, c: 7 },
      { a: 1, b: 4, c: 8 },
      { a: 2, b: 5, c: 9 },
    ]
    */

    两种方法都将一个选项对象作为第二个参数,该对象允许指定 mode"shortest"(默认)、"longest""strict"

    对于 "longest",选项对象还可以通过提供可迭代对象或对象(分别用于 zipzipKeyed)来定义用于较短输入的填充:

    Iterator.zipKeyed({
      a: [0, 1, 2],
      b: [3, 4, 5, 6],
      c: [7, 8, 9],
    }, {
      mode: 'longest',
      padding: { c: 10 },
    }).toArray()
    
    /*
    产生:
    [
      { a: 0,         b: 3, c: 7  },
      { a: 1,         b: 4, c: 8  },
      { a: 2,         b: 5, c: 9  },
      { a: undefined, b: 6, c: 10 },
    ];
    */

    考虑的设计空间

    1. 我们是只支持2个迭代器还是支持其他?2个以上?1个以上?0个以上?决定:0个以上。
      1. 如果允许0个,那被认为是永不完结的还是已经完成的?决定:已经完成。
      2. 迭代器应该按位置传递(组合成数组)还是按名称传递(组合成对象)?决定:两者都支持,作为独立的API。
      3. 我们是将迭代器作为可变参数还是作为可迭代对象/对象?决定:可迭代对象/对象。
        1. 可变参数消除了可能传递选项对象或组合函数的设计空间。
    2. 我们是否支持像 Iterator.fromflatMap 那样的迭代器和可迭代对象?决定:仅支持可迭代对象。
      1. 如果是,我们匹配哪种字符串处理?Iterator.from 迭代字符串;flatMap 拒绝字符串。
    3. 如果某个迭代器完成,我们是否仍然推进其他迭代器?决定:取决于模式。
      1. 我们是否 return 它们?决定:是,除了模式为 longest 时。
    4. 如果某个迭代器推进失败,我们是否仍然推进其他迭代器?决定:是。
      1. 如果是,我们是否返回 AggregateError?仅当有2个或更多失败时?决定:不,第一个错误会吞掉任何后续错误。
    5. 我们是否想要 -With 变体来以元组之外的方式组合值?决定:本次提案不包含。
      1. 那始终要求组合函数呢?
    6. 我们是否想要 zipLongest/zipFilled/zipAll决定:是,作为选项。
      1. 如果是,我们想要一个填充元素还是调用一个函数来提供填充?决定:每个可迭代对象的填充元素。
      2. 那一个匹配特权迭代器(this)长度的变体呢?决定:不。
    7. 我们是否想要一个 zipEqual/zipStrict,如果它们在相同次数的产出后未完成则抛出异常?决定:是,作为选项。

    先前技术

    其他语言

    语言最短最长特权严格-With3+源1源0源
    C++std::ranges::views::zip::zip_transformyesyes
    Clojurevariadic mapyesyesyes
    ElmList.map2yesyes
    HaskellzipzipWithyes
    OCamlzipcombinemap2yes
    Pythonzipitertools.zip_longestzip(..., strict=True)yesyesyes, empty
    RubyEnumerable#zipzipyesyes
    RustIterator::zip
    Scalazipit.zipAll(jt, x, y)
    Swiftzip

    JS 库

    最短最长特权严格-With3+源1源0源
    @iterable-iterator/zipzipzipLongestyesyes
    @softwareventures/iteratorzipOnce
    extra-iterablezipzipzipyesyesyes, empty
    immutable.jsSeq::zipzipWithyesyes
    iter-opszipyesyesyes, empty
    iter-toolszipzipAllyesyesyes, empty
    iterablefuzipzipAllyesyesyes, empty
    iterarezip
    itertools-tszipzipFilled, zipLongestzipEqualyesyesyes, empty
    ixjszipyesyesyes, empty
    lodashzipzipWithyesyesyes, empty
    ramdazipzipWith
    sequencyzip
    wuzipzipLongestzipWithyesyes
    zipiteratorszipiterators