Skip to content

Commit f1b3525

Browse files
authored
feat(collections/unstable): support iterators in sortBy() (#5919)
* feat(collections/sortBy): support iterators * update jsdoc * cleanup * add experimental tag
1 parent 7f4d35c commit f1b3525

File tree

4 files changed

+406
-0
lines changed

4 files changed

+406
-0
lines changed

collections/deno.json

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
"./take-last-while": "./take_last_while.ts",
4747
"./take-while": "./take_while.ts",
4848
"./union": "./union.ts",
49+
"./unstable-sort-by": "./unstable_sort_by.ts",
4950
"./unstable-take-while": "./unstable_take_while.ts",
5051
"./unzip": "./unzip.ts",
5152
"./without-all": "./without_all.ts",

collections/sort_by.ts

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export type SortByOptions = {
2020
* element. Ascending or descending order can be specified through the `order`
2121
* option. By default, the elements are sorted in ascending order.
2222
*
23+
* Note: If you want to process any iterable, use the new version of
24+
* `sortBy` from `@std/collections/unstable-sort-by`.
25+
*
2326
* @typeParam T The type of the array elements.
2427
*
2528
* @param array The array to sort.

collections/sort_by_test.ts

+253
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import { assertEquals } from "@std/assert";
44
import { sortBy } from "./sort_by.ts";
5+
import { sortBy as unstableSortBy } from "./unstable_sort_by.ts";
56

67
Deno.test({
78
name: "sortBy() handles no mutation",
@@ -221,3 +222,255 @@ Deno.test({
221222
);
222223
},
223224
});
225+
226+
Deno.test({
227+
name: "(unstable) sortBy() handles no mutation",
228+
fn() {
229+
const array = ["a", "abc", "ba"];
230+
unstableSortBy(array, (it) => it.length);
231+
232+
assertEquals(array, ["a", "abc", "ba"]);
233+
},
234+
});
235+
236+
Deno.test({
237+
name: "(unstable) sortBy() calls the selector function once",
238+
fn() {
239+
let callCount = 0;
240+
const array = [0, 1, 2];
241+
unstableSortBy(array, (it) => {
242+
callCount++;
243+
return it;
244+
});
245+
246+
assertEquals(callCount, array.length);
247+
},
248+
});
249+
250+
Deno.test({
251+
name: "(unstable) sortBy() handles empty input",
252+
fn() {
253+
assertEquals(unstableSortBy([], () => 5), []);
254+
},
255+
});
256+
257+
Deno.test({
258+
name: "(unstable) sortBy() handles identity selector",
259+
fn() {
260+
assertEquals(unstableSortBy([2, 3, 1], (it) => it), [1, 2, 3]);
261+
},
262+
});
263+
264+
Deno.test({
265+
name: "(unstable) sortBy() handles stable sort",
266+
fn() {
267+
assertEquals(
268+
unstableSortBy([
269+
{ id: 1, date: "February 1, 2022" },
270+
{ id: 2, date: "December 17, 1995" },
271+
{ id: 3, date: "June 12, 2012" },
272+
{ id: 4, date: "December 17, 1995" },
273+
{ id: 5, date: "June 12, 2012" },
274+
], (it) => new Date(it.date)),
275+
[
276+
{ id: 2, date: "December 17, 1995" },
277+
{ id: 4, date: "December 17, 1995" },
278+
{ id: 3, date: "June 12, 2012" },
279+
{ id: 5, date: "June 12, 2012" },
280+
{ id: 1, date: "February 1, 2022" },
281+
],
282+
);
283+
284+
assertEquals(
285+
unstableSortBy([
286+
{ id: 1, str: "c" },
287+
{ id: 2, str: "a" },
288+
{ id: 3, str: "b" },
289+
{ id: 4, str: "a" },
290+
{ id: 5, str: "b" },
291+
], (it) => it.str),
292+
[
293+
{ id: 2, str: "a" },
294+
{ id: 4, str: "a" },
295+
{ id: 3, str: "b" },
296+
{ id: 5, str: "b" },
297+
{ id: 1, str: "c" },
298+
],
299+
);
300+
},
301+
});
302+
303+
Deno.test({
304+
name: "(unstable) sortBy() handles special number values",
305+
fn() {
306+
assertEquals(
307+
unstableSortBy([
308+
1,
309+
Number.POSITIVE_INFINITY,
310+
2,
311+
Number.NEGATIVE_INFINITY,
312+
3,
313+
Number.NaN,
314+
4,
315+
Number.NaN,
316+
], (it) => it),
317+
[
318+
Number.NEGATIVE_INFINITY,
319+
1,
320+
2,
321+
3,
322+
4,
323+
Number.POSITIVE_INFINITY,
324+
Number.NaN,
325+
Number.NaN,
326+
],
327+
);
328+
329+
assertEquals(
330+
unstableSortBy([
331+
Number.NaN,
332+
1,
333+
Number.POSITIVE_INFINITY,
334+
Number.NaN,
335+
7,
336+
Number.NEGATIVE_INFINITY,
337+
Number.NaN,
338+
2,
339+
6,
340+
5,
341+
9,
342+
], (it) => it),
343+
[
344+
Number.NEGATIVE_INFINITY,
345+
1,
346+
2,
347+
5,
348+
6,
349+
7,
350+
9,
351+
Number.POSITIVE_INFINITY,
352+
Number.NaN,
353+
Number.NaN,
354+
Number.NaN,
355+
],
356+
);
357+
358+
// Test that NaN sort is stable.
359+
const nanArray = [
360+
{ id: 1, nan: Number.NaN },
361+
{ id: 2, nan: Number.NaN },
362+
{ id: 3, nan: Number.NaN },
363+
{ id: 4, nan: Number.NaN },
364+
];
365+
assertEquals(unstableSortBy(nanArray, ({ nan }) => nan), nanArray);
366+
},
367+
});
368+
369+
Deno.test({
370+
name: "(unstable) sortBy() handles sortings",
371+
fn() {
372+
const testArray = [
373+
{ name: "benchmark", stage: 3 },
374+
{ name: "test", stage: 2 },
375+
{ name: "build", stage: 1 },
376+
{ name: "deploy", stage: 4 },
377+
];
378+
379+
assertEquals(unstableSortBy(testArray, (it) => it.stage), [
380+
{ name: "build", stage: 1 },
381+
{ name: "test", stage: 2 },
382+
{ name: "benchmark", stage: 3 },
383+
{ name: "deploy", stage: 4 },
384+
]);
385+
386+
assertEquals(unstableSortBy(testArray, (it) => it.name), [
387+
{ name: "benchmark", stage: 3 },
388+
{ name: "build", stage: 1 },
389+
{ name: "deploy", stage: 4 },
390+
{ name: "test", stage: 2 },
391+
]);
392+
393+
assertEquals(
394+
unstableSortBy([
395+
"9007199254740999",
396+
"9007199254740991",
397+
"9007199254740995",
398+
], (it) => BigInt(it)),
399+
[
400+
"9007199254740991",
401+
"9007199254740995",
402+
"9007199254740999",
403+
],
404+
);
405+
406+
assertEquals(
407+
unstableSortBy([
408+
"February 1, 2022",
409+
"December 17, 1995",
410+
"June 12, 2012",
411+
], (it) => new Date(it)),
412+
[
413+
"December 17, 1995",
414+
"June 12, 2012",
415+
"February 1, 2022",
416+
],
417+
);
418+
},
419+
});
420+
421+
Deno.test({
422+
name: "(unstable) sortBy() handles desc ordering",
423+
fn() {
424+
assertEquals(
425+
unstableSortBy(
426+
[
427+
"January 27, 1995",
428+
"November 26, 2020",
429+
"June 17, 1952",
430+
"July 15, 1993",
431+
],
432+
(it) => new Date(it),
433+
{ order: "desc" },
434+
),
435+
[
436+
"November 26, 2020",
437+
"January 27, 1995",
438+
"July 15, 1993",
439+
"June 17, 1952",
440+
],
441+
);
442+
},
443+
});
444+
445+
Deno.test({
446+
name: "(unstable) sortBy() works with iterators",
447+
fn() {
448+
const set = new Set([10, 312, 99, 5.45, 100, -3, 4.6]);
449+
450+
assertEquals(
451+
unstableSortBy(set, (it) => it),
452+
[-3, 4.6, 5.45, 10, 99, 100, 312],
453+
);
454+
assertEquals(
455+
unstableSortBy(set, (it) => it, { order: "desc" }),
456+
[312, 100, 99, 10, 5.45, 4.6, -3],
457+
);
458+
459+
const map = new Map([
460+
["a", 2],
461+
["c", 1],
462+
["b", 3],
463+
]);
464+
465+
assertEquals(unstableSortBy(map, (it) => it[0]), [
466+
["a", 2],
467+
["b", 3],
468+
["c", 1],
469+
]);
470+
assertEquals(unstableSortBy(map, (it) => it[1], { order: "desc" }), [
471+
["b", 3],
472+
["a", 2],
473+
["c", 1],
474+
]);
475+
},
476+
});

0 commit comments

Comments
 (0)