Skip to content

Commit c2ec011

Browse files
feat(arrays): Add index to callbacks
Add index argument to iterable callbacks. re #11
1 parent 7e7cce4 commit c2ec011

File tree

2 files changed

+111
-33
lines changed

2 files changed

+111
-33
lines changed

src/arrays.ts

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ export function ofIterable<T>(source: Iterable<T>): T[] {
1010
* Creates a new array whose elements are the results of applying the specified mapping to each of the elements of the source collection.
1111
* @param mapping A function to transform items from the input collection.
1212
*/
13-
export function map<T, U>(mapping: (item: T) => U): (source: T[]) => U[]
13+
export function map<T, U>(mapping: (item: T, index: number) => U): (source: T[]) => U[]
1414
/**
1515
* Creates a new array whose elements are the results of applying the specified mapping to each of the elements of the source collection.
1616
* @param source The input collection.
1717
* @param mapping A function to transform items from the input collection.
1818
*/
19-
export function map<T, U>(source: T[], mapping: (item: T) => U): U[]
19+
export function map<T, U>(source: T[], mapping: (item: T, index: number) => U): U[]
2020
export function map<T, U>(a: any, b?: any): any {
2121
const partial = typeof a === 'function'
22-
const mapping: (item: T) => U = partial ? a : b
22+
const mapping: (item: T, index: number) => U = partial ? a : b
2323
function exec(source: T[]) {
2424
return source.map(mapping)
2525
}
@@ -30,16 +30,16 @@ export function map<T, U>(a: any, b?: any): any {
3030
* Returns a new array containing only the elements of the collection for which the given predicate returns true.
3131
* @param predicate A function to test whether each item in the input collection should be included in the output.
3232
*/
33-
export function filter<T>(predicate: (item: T) => boolean): (source: T[]) => T[]
33+
export function filter<T>(predicate: (item: T, index: number) => boolean): (source: T[]) => T[]
3434
/**
3535
* Returns a new array containing only the elements of the collection for which the given predicate returns true.
3636
* @param source The input collection.
3737
* @param predicate A function to test whether each item in the input collection should be included in the output.
3838
*/
39-
export function filter<T>(source: T[], predicate: (item: T) => boolean): T[]
39+
export function filter<T>(source: T[], predicate: (item: T, index: number) => boolean): T[]
4040
export function filter<T, U>(a: any, b?: any): any {
4141
const partial = typeof a === 'function'
42-
const predicate: (item: T) => boolean = partial ? a : b
42+
const predicate: (item: T, index: number) => boolean = partial ? a : b
4343
function exec(source: T[]) {
4444
return source.filter(predicate)
4545
}
@@ -50,23 +50,27 @@ export function filter<T, U>(a: any, b?: any): any {
5050
* Applies the given function to each element of the array and returns a new array comprised of the results for each element where the function returns a value.
5151
* @param chooser A function to transform items from the input collection to a new value to be included, or undefined to be excluded.
5252
*/
53-
export function choose<T, U>(chooser: (item: T) => U | undefined): (source: T[]) => U[]
53+
export function choose<T, U>(
54+
chooser: (item: T, index: number) => U | undefined
55+
): (source: T[]) => U[]
5456
/**
5557
* Applies the given function to each element of the array and returns a new array comprised of the results for each element where the function returns a value.
5658
* @param source The input collection.
5759
* @param chooser A function to transform items from the input collection to a new value to be included, or undefined to be excluded.
5860
*/
59-
export function choose<T, U>(source: T[], chooser: (item: T) => U | undefined): U[]
61+
export function choose<T, U>(source: T[], chooser: (item: T, index: number) => U | undefined): U[]
6062
export function choose<T, U>(a: any, b?: any): any {
6163
const partial = typeof a === 'function'
62-
const chooser: (item: T) => U | undefined = partial ? a : b
64+
const chooser: (item: T, index: number) => U | undefined = partial ? a : b
6365
function exec(source: T[]) {
6466
const target = []
67+
let index = 0
6568
for (const item of source) {
66-
const chosen = chooser(item)
69+
const chosen = chooser(item, index)
6770
if (chosen !== undefined) {
6871
target.push(chosen)
6972
}
73+
index++
7074
}
7175
return target
7276
}
@@ -77,23 +81,27 @@ export function choose<T, U>(a: any, b?: any): any {
7781
* Applies the given function to each element of the source array and concatenates all the results.
7882
* @param mapping A function to transform elements of the input collection into collections that are concatenated.
7983
*/
80-
export function collect<T, U>(mapping: (item: T) => Iterable<U>): (source: T[]) => U[]
84+
export function collect<T, U>(
85+
mapping: (item: T, index: number) => Iterable<U>
86+
): (source: T[]) => U[]
8187
/**
8288
* Applies the given function to each element of the source array and concatenates all the results.
8389
* @param source The input collection.
8490
* @param mapping A function to transform elements of the input collection into collections that are concatenated.
8591
*/
86-
export function collect<T, U>(source: T[], mapping: (item: T) => Iterable<U>): U[]
92+
export function collect<T, U>(source: T[], mapping: (item: T, index: number) => Iterable<U>): U[]
8793
export function collect<T, U>(a: any, b?: any): any {
8894
const partial = typeof a === 'function'
89-
const mapping: (item: T) => Iterable<U> = partial ? a : b
95+
const mapping: (item: T, index: number) => Iterable<U> = partial ? a : b
9096
function exec(source: T[]) {
9197
const target = []
98+
let index = 0
9299
for (const item of source) {
93-
const children = mapping(item)
100+
const children = mapping(item, index)
94101
for (const child of children) {
95102
target.push(child)
96103
}
104+
index++
97105
}
98106
return target
99107
}
@@ -142,25 +150,27 @@ export function concat<T>(sources: Iterable<T[]>): T[] {
142150
* @param selector A function that transforms the array items into comparable keys.
143151
* @param source The input collection.
144152
*/
145-
export function distinctBy<T, Key>(selector: (item: T) => Key): (source: T[]) => T[]
153+
export function distinctBy<T, Key>(selector: (item: T, index: number) => Key): (source: T[]) => T[]
146154
/**
147155
* Returns an array that contains no duplicate entries according to the equality comparisons on
148156
* the keys returned by the given key-generating function. If an element occurs multiple times in
149157
* the sequence then the later occurrences are discarded.
150158
* @param source The input collection.
151159
* @param selector A function that transforms the array items into comparable keys.
152160
*/
153-
export function distinctBy<T, Key>(source: T[], selector: (item: T) => Key): T[]
161+
export function distinctBy<T, Key>(source: T[], selector: (item: T, index: number) => Key): T[]
154162
export function distinctBy<T, Key>(a: any, b?: any): any {
155163
const partial = typeof a === 'function'
156-
const selector: (item: T) => Key = partial ? a : b
164+
const selector: (item: T, index: number) => Key = partial ? a : b
157165
function exec(source: T[]): T[] {
158166
const seen = new Map<Key, T>()
167+
let index = 0
159168
for (const item of source) {
160-
const key = selector(item)
169+
const key = selector(item, index)
161170
if (!seen.has(key)) {
162171
seen.set(key, item)
163172
}
173+
index++
164174
}
165175
return Array.from(seen.values())
166176
}
@@ -172,16 +182,16 @@ export function distinctBy<T, Key>(a: any, b?: any): any {
172182
* @param predicate A function to test each item of the input collection.
173183
* @param source The input collection.
174184
*/
175-
export function exists<T>(predicate: (item: T) => boolean): (source: T[]) => boolean
185+
export function exists<T>(predicate: (item: T, index: number) => boolean): (source: T[]) => boolean
176186
/**
177187
* Tests if any element of the array satisfies the given predicate.
178188
* @param source The input collection.
179189
* @param predicate A function to test each item of the input collection.
180190
*/
181-
export function exists<T>(source: T[], predicate: (item: T) => boolean): boolean
191+
export function exists<T>(source: T[], predicate: (item: T, index: number) => boolean): boolean
182192
export function exists<T>(a: any, b?: any): any {
183193
const partial = typeof a === 'function'
184-
const predicate: (item: T) => boolean = partial ? a : b
194+
const predicate: (item: T, index: number) => boolean = partial ? a : b
185195
function exec(source: T[]): boolean {
186196
return source.some(predicate)
187197
}
@@ -194,22 +204,24 @@ export function exists<T>(a: any, b?: any): any {
194204
* @param source The input collection.
195205
* @throws If no item is found matching the criteria of the predicate.
196206
*/
197-
export function get<T>(predicate: (item: T) => boolean): (source: T[]) => T
207+
export function get<T>(predicate: (item: T, index: number) => boolean): (source: T[]) => T
198208
/**
199209
* Returns the first element for which the given function returns true.
200210
* @param source The input collection.
201211
* @param predicate A function to test whether an item in the collection should be returned.
202212
* @throws If no item is found matching the criteria of the predicate.
203213
*/
204-
export function get<T>(source: T[], predicate: (item: T) => boolean): T
214+
export function get<T>(source: T[], predicate: (item: T, index: number) => boolean): T
205215
export function get<T>(a: any, b?: any): any {
206216
const partial = typeof a === 'function'
207-
const predicate: (item: T) => boolean = partial ? a : b
217+
const predicate: (item: T, index: number) => boolean = partial ? a : b
208218
function exec(source: T[]): T | undefined {
219+
let index = 0
209220
for (const item of source) {
210-
if (predicate(item)) {
221+
if (predicate(item, index)) {
211222
return item
212223
}
224+
index++
213225
}
214226
throw new Error('Element not found matching criteria')
215227
}
@@ -221,42 +233,53 @@ export function get<T>(a: any, b?: any): any {
221233
* @param predicate A function to test whether an item in the collection should be returned.
222234
* @param source The input collection.
223235
*/
224-
export function find<T>(predicate: (item: T) => boolean): (source: T[]) => T | undefined
236+
export function find<T>(
237+
predicate: (item: T, index: number) => boolean
238+
): (source: T[]) => T | undefined
225239
/**
226240
* Returns the first element for which the given function returns true, otherwise undefined.
227241
* @param source The input collection.
228242
* @param predicate A function to test whether an item in the collection should be returned.
229243
*/
230-
export function find<T>(source: T[], predicate: (item: T) => boolean): T | undefined
244+
export function find<T>(source: T[], predicate: (item: T, index: number) => boolean): T | undefined
231245
export function find<T>(a: any, b?: any): any {
232246
const partial = typeof a === 'function'
233-
const predicate: (item: T) => boolean = partial ? a : b
247+
const predicate: (item: T, index: number) => boolean = partial ? a : b
234248
function exec(source: T[]): T | undefined {
249+
let index = 0
235250
for (const item of source) {
236-
if (predicate(item)) {
251+
if (predicate(item, index)) {
237252
return item
238253
}
254+
index++
239255
}
240256
return undefined
241257
}
242258
return partial ? exec : exec(a)
243259
}
244260

245-
export function groupBy<T, Key>(selector: (item: T) => Key): (source: T[]) => [Key, T[]][]
246-
export function groupBy<T, Key>(source: T[], selector: (item: T) => Key): [Key, T[]][]
261+
export function groupBy<T, Key>(
262+
selector: (item: T, index: number) => Key
263+
): (source: T[]) => [Key, T[]][]
264+
export function groupBy<T, Key>(
265+
source: T[],
266+
selector: (item: T, index: number) => Key
267+
): [Key, T[]][]
247268
export function groupBy<T, Key>(a: any, b?: any): any {
248269
const partial = typeof a === 'function'
249-
const selector: (item: T) => Key = partial ? a : b
270+
const selector: (item: T, index: number) => Key = partial ? a : b
250271
function exec(source: T[]): [Key, T[]][] {
251272
const groups = new Map<Key, T[]>()
273+
let index = 0
252274
for (const item of source) {
253-
const key = selector(item)
275+
const key = selector(item, index)
254276
const group = groups.get(key)
255277
if (group === undefined) {
256278
groups.set(key, [item])
257279
} else {
258280
group.push(item)
259281
}
282+
index++
260283
}
261284
return Array.from(groups.entries())
262285
}

test/arrays.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ describe('map', () => {
2020
test('invoke', () => {
2121
expect(Arrays.map([1, 2], x => x * 2)).toEqual([2, 4])
2222
})
23+
test('with index', () => {
24+
expect(Arrays.map([1, 2], (x, index) => x * index)).toEqual([0, 2])
25+
})
2326
})
2427

2528
describe('filter', () => {
@@ -32,6 +35,9 @@ describe('filter', () => {
3235
test('invoke', () => {
3336
expect(Arrays.filter([1, 2, 3, 4], x => x % 2 === 0)).toEqual([2, 4])
3437
})
38+
test('with index', () => {
39+
expect(Arrays.filter([1, 2, 3, 4], (x, index) => index % 2 === 0)).toEqual([1, 3])
40+
})
3541
})
3642

3743
describe('choose', () => {
@@ -43,6 +49,11 @@ describe('choose', () => {
4349
test('invoke', () => {
4450
expect(Arrays.choose([1, 2, 3], x => (x % 2 === 1 ? x * 2 : undefined))).toEqual([2, 6])
4551
})
52+
test('with index', () => {
53+
expect(
54+
Arrays.choose([1, 2, 3], (x, index) => (index % 2 === 0 ? x * index : undefined))
55+
).toEqual([0, 6])
56+
})
4657
})
4758

4859
describe('collect', () => {
@@ -62,6 +73,13 @@ describe('collect', () => {
6273
})
6374
).toEqual([1, 1, 2, 2])
6475
})
76+
test('with index', () => {
77+
expect(
78+
Arrays.collect([1, 2], function(x, index) {
79+
return [x, x + index]
80+
})
81+
).toEqual([1, 1, 2, 3])
82+
})
6583
})
6684

6785
describe('append', () => {
@@ -101,6 +119,19 @@ describe('distinctBy', () => {
101119
)
102120
).toEqual([{ name: 'amy', id: 1 }, { name: 'bob', id: 2 }, { name: 'cat', id: 3 }])
103121
})
122+
test('with index', () => {
123+
expect(
124+
pipe(
125+
[
126+
{ name: 'amy', id: 1 },
127+
{ name: 'bob', id: 2 },
128+
{ name: 'bob', id: 3 },
129+
{ name: 'cat', id: 3 }
130+
],
131+
Arrays.distinctBy((x, index) => Math.floor(index / 2))
132+
)
133+
).toEqual([{ name: 'amy', id: 1 }, { name: 'bob', id: 3 }])
134+
})
104135
})
105136

106137
describe('exists', () => {
@@ -113,6 +144,9 @@ describe('exists', () => {
113144
test('invoke', () => {
114145
expect(Arrays.exists([1, 2], x => x === 1)).toEqual(true)
115146
})
147+
test('with index', () => {
148+
expect(Arrays.exists([1, 2], (x, index) => index === 1)).toEqual(true)
149+
})
116150
})
117151

118152
describe('get', () => {
@@ -135,6 +169,11 @@ describe('get', () => {
135169
Arrays.get([{ name: 'amy', id: 1 }, { name: 'bob', id: 2 }], x => x.name === 'bob')
136170
).toEqual({ name: 'bob', id: 2 })
137171
})
172+
test('by index', () => {
173+
expect(
174+
Arrays.get([{ name: 'amy', id: 1 }, { name: 'bob', id: 2 }], (x, index) => index === 1)
175+
).toEqual({ name: 'bob', id: 2 })
176+
})
138177
})
139178

140179
describe('find', () => {
@@ -157,6 +196,11 @@ describe('find', () => {
157196
Arrays.find([{ name: 'amy', id: 1 }, { name: 'bob', id: 2 }], x => x.name === 'bob')
158197
).toEqual({ name: 'bob', id: 2 })
159198
})
199+
test('by index', () => {
200+
expect(
201+
Arrays.find([{ name: 'amy', id: 1 }, { name: 'bob', id: 2 }], (x, index) => index === 1)
202+
).toEqual({ name: 'bob', id: 2 })
203+
})
160204
})
161205

162206
describe('groupBy', () => {
@@ -181,6 +225,17 @@ describe('groupBy', () => {
181225
[2, [{ name: 'bob', age: 2 }, { name: 'cat', age: 2 }]]
182226
])
183227
})
228+
test('with index', () => {
229+
expect(
230+
Arrays.groupBy(
231+
[{ name: 'amy', age: 1 }, { name: 'bob', age: 2 }, { name: 'cat', age: 2 }],
232+
(x, index) => index % 2
233+
)
234+
).toEqual([
235+
[0, [{ name: 'amy', age: 1 }, { name: 'cat', age: 2 }]],
236+
[1, [{ name: 'bob', age: 2 }]]
237+
])
238+
})
184239
})
185240

186241
describe('init', () => {

0 commit comments

Comments
 (0)