1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98 |
x4
x4
x18
x18
x17
x17
x17
x18
x40
x40
x40
x40
x17
x18
x10
x10
x10
x10
x10
x22
x22
x22
x10
x3
x3
x10
x5
x5
x10
x10
x7
x16
x15
x41
x33
x33
x41
x15
x7
x18 |
|
// Copyright 2018-2026 the Deno authors. MIT license.
// This module is browser compatible.
/**
* Returns all elements from the given iterables in round-robin order.
* Unlike {@linkcode zip}, which stops at the shortest iterable and returns
* tuples, `interleave` continues until all input iterables are exhausted and
* returns a flat array. All input iterables are consumed eagerly.
*
* @experimental **UNSTABLE**: New API, yet to be vetted.
*
* @typeParam T The tuple of element types in the input iterables.
*
* @param iterables The iterables to interleave.
* @returns A new array containing all elements from the input iterables in
* round-robin order.
*
* @example Basic usage
* ```ts
* import { interleave } from "@std/collections/unstable-interleave";
* import { assertEquals } from "@std/assert";
*
* const numbers = [1, 2, 3];
* const letters = ["a", "b", "c"];
*
* assertEquals(interleave(numbers, letters), [1, "a", 2, "b", 3, "c"]);
* ```
*
* @example Unequal-length arrays
* ```ts
* import { interleave } from "@std/collections/unstable-interleave";
* import { assertEquals } from "@std/assert";
*
* assertEquals(
* interleave([1, 2, 3], ["a", "b"], [true]),
* [1, "a", true, 2, "b", 3],
* );
* ```
*
* @example With iterables
* ```ts
* import { interleave } from "@std/collections/unstable-interleave";
* import { assertEquals } from "@std/assert";
*
* assertEquals(
* interleave(new Set([1, 2, 3]), ["a", "b", "c"]),
* [1, "a", 2, "b", 3, "c"],
* );
* ```
*/
export function interleave<T extends unknown[]>(
...iterables: { [K in keyof T]: Iterable<T[K]> }
): T[number][] {
const arrayCount = iterables.length;
if (arrayCount === 0) return [];
const arrays = iterables.map((it) => Array.isArray(it) ? it : Array.from(it));
let maxLength = 0;
let totalLength = 0;
for (let i = 0; i < arrayCount; ++i) {
const len = arrays[i]!.length;
totalLength += len;
if (len > maxLength) maxLength = len;
}
const result: T[number][] = new Array(totalLength);
// Fast path for two arrays
if (arrayCount === 2) {
const a = arrays[0]!;
const b = arrays[1]!;
const minLen = Math.min(a.length, b.length);
let k = 0;
for (let i = 0; i < minLen; ++i) {
result[k++] = a[i] as T[number];
result[k++] = b[i] as T[number];
}
for (let i = minLen; i < a.length; ++i) {
result[k++] = a[i] as T[number];
}
for (let i = minLen; i < b.length; ++i) {
result[k++] = b[i] as T[number];
}
return result;
}
let k = 0;
for (let i = 0; i < maxLength; ++i) {
for (let j = 0; j < arrayCount; ++j) {
if (i < arrays[j]!.length) {
result[k++] = arrays[j]![i] as T[number];
}
}
}
return result;
}
|