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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// Grouping and index building.
//
// Spliced into the `FluentIter` trait by `build.rs`. Names resolve in
// the crate-root scope of `lib.rs`, exactly as before the split.
/// ⇔ `.group(keyFn)`: **stable** grouping — first-seen key order is
/// preserved and each group keeps encounter order.
///
/// Note [`Iterator::group_by`] only groups *consecutive* elements,
/// which is a different operation (that one is `slice::group_by`
/// territory); this is the npm `group`, which is a full pass.
///
/// ```
/// use fluent_iterable::FluentIter;
///
/// let grouped = ["b", "a", "b", "c", "a"].into_iter().group_by_stable(|x| *x);
/// let keys: Vec<_> = grouped.iter().map(|(k, _)| *k).collect();
/// assert_eq!(keys, vec!["b", "a", "c"]);
/// assert_eq!(grouped[1].1, vec!["a", "a"]);
/// ```
///
/// Resolving: grouping is O(N) by nature — an element can extend a
/// group that was opened first, so no group is final before the whole
/// source is read. The `Vec` costs the same memory as any buffering
/// adapter and stays re-iterable; chain it with `.into_iter()` when you
/// want adapters over the groups.
/// ⇔ `.toMap(keyFn, valueFn)`: later entries overwrite earlier ones for
/// the same key (JS `Map.set` semantics; `HashMap` iteration order is
/// unspecified, like the JS engine's).
///
/// ```
/// use fluent_iterable::FluentIter;
///
/// let items = vec![("k", 1), ("j", 2), ("k", 3)];
/// let map = items.into_iter().to_map_by(|(k, _)| *k, |(_, v)| *v);
/// assert_eq!(map.get("k"), Some(&3));
/// ```
/// ⇔ `.toMapChain(k1, k2)`: two-level index — `key1` outer, `key2`
/// inner, leaves keep encounter order.
///
/// JS chains to an arbitrary number of key functions; Rust fixes the
/// nested type at depth 2 — deeper nesting is a fold of these layers.
///
/// ```
/// use fluent_iterable::FluentIter;
///
/// let rows = [("sp", "sa", 1), ("sp", "rj", 2), ("mg", "sa", 3)];
/// let index = rows
/// .into_iter()
/// .to_map_chain(|(a, _, _)| *a, |(_, b, _)| *b);
/// assert_eq!(index["sp"]["sa"], vec![("sp", "sa", 1)]);
/// assert_eq!(index["sp"]["rj"], vec![("sp", "rj", 2)]);
/// ```
/// ⇔ `.toMapChainReduce(k1, k2, reducer)`: two-level index whose leaves
/// are folded instead of collected. JS folds without an explicit
/// initial value; Rust demands one (there is no `undefined`).
///
/// ```
/// use fluent_iterable::FluentIter;
///
/// let rows = [("sp", "sa", 1), ("sp", "sa", 2), ("sp", "rj", 5)];
/// let totals = rows.into_iter().to_map_chain_reduce(
/// |(a, _, _)| *a,
/// |(_, b, _)| *b,
/// 0,
/// |acc, (_, _, v)| acc + v,
/// );
/// assert_eq!(totals["sp"]["sa"], 3);
/// assert_eq!(totals["sp"]["rj"], 5);
/// ```