-
Notifications
You must be signed in to change notification settings - Fork 72
/
orderby.ts
119 lines (103 loc) · 3.82 KB
/
orderby.ts
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
import { IterableX } from './iterablex';
import { sorter as defaultSorter } from '../internal/sorter';
export abstract class OrderedIterableBaseX<TSource> extends IterableX<TSource> {
_source: Iterable<TSource>;
constructor(source: Iterable<TSource>) {
super();
this._source = source;
}
*[Symbol.iterator]() {
const array = Array.from<TSource>(this._source);
const len = array.length;
const indices = new Array<number>(len);
for (let i = 0, len = array.length; i < len; i++) {
indices[i] = i;
}
indices.sort(this._getSorter(array));
for (const index of indices) {
yield array[index];
}
}
thenBy<TKey>(
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableBaseX<TSource> {
/* tslint:disable-next-line: no-use-before-declare */
return new OrderedIterableX<TKey, TSource>(this._source, keySelector, comparer, false, this);
}
thenByDescending<TKey>(
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableBaseX<TSource> {
/* tslint:disable-next-line: no-use-before-declare */
return new OrderedIterableX<TKey, TSource>(this._source, keySelector, comparer, true, this);
}
abstract _getSorter(
elements: TSource[],
next?: (x: number, y: number) => number
): (x: number, y: number) => number;
}
export class OrderedIterableX<TKey, TSource> extends OrderedIterableBaseX<TSource> {
private _keySelector: (item: TSource) => TKey;
private _comparer: (fst: TKey, snd: TKey) => number;
private _descending: boolean;
private _parent?: OrderedIterableBaseX<TSource>;
constructor(
source: Iterable<TSource>,
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number,
descending: boolean,
parent?: OrderedIterableBaseX<TSource>
) {
super(source);
this._keySelector = keySelector;
this._comparer = comparer;
this._descending = descending;
this._parent = parent;
}
_getSorter(
elements: TSource[],
next?: (x: number, y: number) => number
): (x: number, y: number) => number {
const keys = elements.map(this._keySelector);
const comparer = this._comparer;
const parent = this._parent;
const descending = this._descending;
const sorter = (x: number, y: number): number => {
const result = comparer(keys[x], keys[y]);
if (result === 0) {
return next ? next(x, y) : x - y;
}
return descending ? -result : result;
};
return parent ? parent._getSorter(elements, sorter) : sorter;
}
}
export function orderBy<TKey, TSource>(
source: Iterable<TSource>,
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableX<TKey, TSource> {
return new OrderedIterableX<TKey, TSource>(source, keySelector, comparer, false);
}
export function orderByDescending<TKey, TSource>(
source: Iterable<TSource>,
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableX<TKey, TSource> {
return new OrderedIterableX<TKey, TSource>(source, keySelector, comparer, true);
}
export function thenBy<TKey, TSource>(
source: OrderedIterableBaseX<TSource>,
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableX<TKey, TSource> {
return new OrderedIterableX<TKey, TSource>(source._source, keySelector, comparer, false, source);
}
export function thenByDescending<TKey, TSource>(
source: OrderedIterableBaseX<TSource>,
keySelector: (item: TSource) => TKey,
comparer: (fst: TKey, snd: TKey) => number = defaultSorter
): OrderedIterableX<TKey, TSource> {
return new OrderedIterableX<TKey, TSource>(source._source, keySelector, comparer, true, source);
}