Skip to content

Commit ee383e0

Browse files
committed
Merge branch 'main' into alpha
2 parents fab52df + 524b670 commit ee383e0

File tree

2 files changed

+169
-10
lines changed

2 files changed

+169
-10
lines changed

index.test.ts

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
contains,
1010
dropWhile,
1111
empty,
12+
equal,
1213
exclude,
1314
excludeFirst,
1415
excludeNull,
@@ -34,6 +35,7 @@ import {
3435
mapKeyFirstBy,
3536
maximum,
3637
minimum,
38+
only,
3739
or,
3840
partition,
3941
partitionWhile,
@@ -46,6 +48,8 @@ import {
4648
scanRight,
4749
scanRight1,
4850
slice,
51+
sort,
52+
sortBy,
4953
split,
5054
sum,
5155
tail,
@@ -85,6 +89,12 @@ test("last", t => {
8589
t.is(last([1, 2, 3]), 3);
8690
});
8791

92+
test("only", t => {
93+
t.is(only([]), null);
94+
t.is(only([4]), 4);
95+
t.is(only([3, 4, 5]), null);
96+
});
97+
8898
test("empty", t => {
8999
t.true(empty([]));
90100
t.false(empty([1, 2, 3]));
@@ -120,6 +130,38 @@ test("dropWhile", t => {
120130
);
121131
});
122132

133+
test("equal", t => {
134+
t.true(equal([1, 2, 3], [1, 2, 3]));
135+
t.false(equal([1, 2, 3], [1, 2, 3, 4]));
136+
t.false(equal([1, 2, 3, 4], [1, 2, 3]));
137+
t.false(equal([1, 3, 3], [1, 2, 3]));
138+
t.true(
139+
equal(
140+
[
141+
[1, 2],
142+
[3, 4]
143+
],
144+
[
145+
[1, 2],
146+
[3, 4]
147+
],
148+
equal
149+
)
150+
);
151+
t.false(
152+
equal(
153+
[
154+
[1, 2],
155+
[3, 4]
156+
],
157+
[
158+
[1, 2],
159+
[3, 4]
160+
]
161+
)
162+
);
163+
});
164+
123165
test("map", t => {
124166
t.deepEqual(
125167
map([1, 2, 3], e => e + 1),
@@ -450,24 +492,57 @@ test("mapKeyBy", t => {
450492
t.deepEqual(Array.from(map.keys()), ["odd", "even"]);
451493
});
452494

495+
test("mapKeyFirstBy", t => {
496+
const map = mapKeyFirstBy([1, 3, 4, 2, 5, 6], e => [e % 2 === 0 ? "even" : "odd", String(e)]);
497+
t.is(map.get("even"), "4");
498+
t.is(map.get("odd"), "1");
499+
t.deepEqual(Array.from(map.keys()), ["odd", "even"]);
500+
});
501+
453502
test("groupByIdentity", t => {
454503
t.deepEqual(
455504
groupByIdentity(["abc", "adef", "bghi"], a => a.substr(0, 1)),
456505
[["abc", "adef"], ["bghi"]]
457506
);
458507
});
459508

509+
test("sort", t => {
510+
t.deepEqual(sort([2, 4, 3, 1]), [1, 2, 3, 4]);
511+
t.deepEqual(sort(["hello", "goodbye"]), ["goodbye", "hello"]);
512+
t.deepEqual(
513+
sort([-2, 4, -3, 1], (a, b) => Math.abs(a) - Math.abs(b)),
514+
[1, -2, -3, 4]
515+
);
516+
});
517+
518+
test("sortBy", t => {
519+
t.deepEqual(
520+
sortBy(
521+
[
522+
{x: "a", y: 2},
523+
{x: "b", y: 4},
524+
{x: "c", y: 3},
525+
{x: "d", y: 1}
526+
],
527+
({y}) => y
528+
),
529+
[
530+
{x: "d", y: 1},
531+
{x: "a", y: 2},
532+
{x: "c", y: 3},
533+
{x: "b", y: 4}
534+
]
535+
);
536+
t.deepEqual(
537+
sortBy([-2, 4, -3, 1], e => Math.abs(e)),
538+
[1, -2, -3, 4]
539+
);
540+
});
541+
460542
test("forEach", t => {
461543
const a = ["a", "b", "c"];
462544
let s = "";
463545
const b = forEach(a, c => (s += c));
464546
t.is(b, a);
465547
t.is(s, "abc");
466548
});
467-
468-
test("mapKeyFirstBy", t => {
469-
const map = mapKeyFirstBy([1, 3, 4, 2, 5, 6], e => [e % 2 === 0 ? "even" : "odd", String(e)]);
470-
t.is(map.get("even"), "4");
471-
t.is(map.get("odd"), "1");
472-
t.deepEqual(Array.from(map.keys()), ["odd", "even"]);
473-
});

index.ts

Lines changed: 87 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ export function last<T>(array: ArrayLike<T>): T | null {
9898
return array.length === 0 ? null : array[array.length - 1];
9999
}
100100

101+
/** If the array contains exactly one element, returns that element.
102+
* Otherwise, returns null. */
103+
export function only<T>(array: ArrayLike<T>): T | null {
104+
return array.length === 1 ? array[0] : null;
105+
}
106+
101107
export function empty<T>(array: ArrayLike<T>): boolean {
102108
return array.length === 0;
103109
}
@@ -182,6 +188,50 @@ export function dropWhileFn<T>(
182188
return array => dropWhile(array, predicate);
183189
}
184190

191+
export function equal<T>(
192+
a: ArrayLike<T>,
193+
b: ArrayLike<T>,
194+
elementsEqual: (a: T, b: T) => boolean = defaultEqual
195+
): boolean {
196+
if (a.length !== b.length) {
197+
return false;
198+
}
199+
200+
for (let i = 0; i < a.length; ++i) {
201+
if (!elementsEqual(a[i], b[i])) {
202+
return false;
203+
}
204+
}
205+
206+
return true;
207+
}
208+
209+
export function equalFn<T>(
210+
b: ArrayLike<T>,
211+
elementsEqual: (a: T, b: T) => boolean = defaultEqual
212+
): (a: ArrayLike<T>) => boolean {
213+
return a => equal(a, b, elementsEqual);
214+
}
215+
216+
export function notEqual<T>(
217+
a: ArrayLike<T>,
218+
b: ArrayLike<T>,
219+
elementsEqual: (a: T, b: T) => boolean = defaultEqual
220+
): boolean {
221+
return !equal(a, b, elementsEqual);
222+
}
223+
224+
export function notEqualFn<T>(
225+
b: ArrayLike<T>,
226+
elementsEqual: (a: T, b: T) => boolean = defaultEqual
227+
): (a: ArrayLike<T>) => boolean {
228+
return a => notEqual(a, b, elementsEqual);
229+
}
230+
231+
function defaultEqual(a: unknown, b: unknown): boolean {
232+
return a === b;
233+
}
234+
185235
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
186236
// @ts-ignore duplicate identifier: This is the exported declaration, the implementation is below.
187237
export function map<T, U>(array: ArrayLike<T>, f: (element: T, index: number) => U): U[];
@@ -792,9 +842,10 @@ export function partitionWhileFn<T>(
792842
* If one of the supplied arrays is shorter than the other, then the excess
793843
* elements of the longer array will be discarded. */
794844
export function zip<T, U>(a: readonly T[], b: readonly U[]): Array<[T, U]> {
795-
const result: Array<[T, U]> = [];
796-
for (let i = 0; i < a.length && i < b.length; ++i) {
797-
result.push([a[i], b[i]]);
845+
const length = Math.min(a.length, b.length);
846+
const result = new Array<[T, U]>(length);
847+
for (let i = 0; i < length; ++i) {
848+
result[i] = [a[i], b[i]];
798849
}
799850
return result;
800851
}
@@ -1463,6 +1514,39 @@ export function shuffle<T>(array: ArrayLike<T>): T[] {
14631514
return result;
14641515
}
14651516

1517+
export function sort(array: ArrayLike<boolean>): boolean[];
1518+
export function sort(array: ArrayLike<number>): number[];
1519+
export function sort(array: ArrayLike<string>): string[];
1520+
export function sort<T>(array: ArrayLike<T>, comparator: Comparator<T>): T[];
1521+
export function sort<T>(array: ArrayLike<T>, comparator?: Comparator<T>): T[] {
1522+
return copy(array).sort(comparator ?? (defaultCompare as any));
1523+
}
1524+
1525+
export function sortFn<T>(comparator: Comparator<T>): (array: ArrayLike<T>) => T[] {
1526+
return array => sort(array, comparator);
1527+
}
1528+
1529+
export function sortBy<T>(array: ArrayLike<T>, select: SortSelect<T>): T[] {
1530+
return sort(array, (a, b) => defaultCompare(select(a) as any, select(b) as any));
1531+
}
1532+
1533+
export function sortByFn<T>(select: SortSelect<T>): (array: ArrayLike<T>) => T[] {
1534+
return array => sortBy(array, select);
1535+
}
1536+
1537+
export function sortByDescending<T>(array: ArrayLike<T>, select: SortSelect<T>): T[] {
1538+
return sort(array, (a, b) => -defaultCompare(select(a) as any, select(b) as any));
1539+
}
1540+
1541+
export function sortByDescendingFn<T>(select: SortSelect<T>): (array: ArrayLike<T>) => T[] {
1542+
return array => sortByDescending(array, select);
1543+
}
1544+
1545+
export type SortSelect<T> =
1546+
| ((element: T) => boolean)
1547+
| ((element: T) => number)
1548+
| ((element: T) => string);
1549+
14661550
export function forEach<T>(
14671551
array: ArrayLike<T>,
14681552
f: (element: T, index: number) => void

0 commit comments

Comments
 (0)