1 | // Copyright (c) Jupyter Development Team.
|
2 | // Distributed under the terms of the Modified BSD License.
|
3 | /*-----------------------------------------------------------------------------
|
4 | | Copyright (c) 2014-2017, PhosphorJS Contributors
|
5 | |
|
6 | | Distributed under the terms of the BSD 3-Clause License.
|
7 | |
|
8 | | The full license is in the file LICENSE, distributed with this software.
|
9 | |----------------------------------------------------------------------------*/
|
10 |
|
11 | /**
|
12 | * Find the first value in an iterable which matches a predicate.
|
13 | *
|
14 | * @param object - The iterable object to search.
|
15 | *
|
16 | * @param fn - The predicate function to apply to the values.
|
17 | *
|
18 | * @returns The first matching value, or `undefined` if no matching
|
19 | * value is found.
|
20 | *
|
21 | * #### Complexity
|
22 | * Linear.
|
23 | *
|
24 | * #### Example
|
25 | * ```typescript
|
26 | * import { find } from '@lumino/algorithm';
|
27 | *
|
28 | * interface IAnimal { species: string, name: string };
|
29 | *
|
30 | * function isCat(value: IAnimal): boolean {
|
31 | * return value.species === 'cat';
|
32 | * }
|
33 | *
|
34 | * let data: IAnimal[] = [
|
35 | * { species: 'dog', name: 'spot' },
|
36 | * { species: 'cat', name: 'fluffy' },
|
37 | * { species: 'alligator', name: 'pocho' }
|
38 | * ];
|
39 | *
|
40 | * find(data, isCat).name; // 'fluffy'
|
41 | * ```
|
42 | */
|
43 | export function find<T>(
|
44 | object: Iterable<T>,
|
45 | fn: (value: T, index: number) => boolean
|
46 | ): T | undefined {
|
47 | let index = 0;
|
48 | for (const value of object) {
|
49 | if (fn(value, index++)) {
|
50 | return value;
|
51 | }
|
52 | }
|
53 | return undefined;
|
54 | }
|
55 |
|
56 | /**
|
57 | * Find the index of the first value which matches a predicate.
|
58 | *
|
59 | * @param object - The iterable object to search.
|
60 | *
|
61 | * @param fn - The predicate function to apply to the values.
|
62 | *
|
63 | * @returns The index of the first matching value, or `-1` if no
|
64 | * matching value is found.
|
65 | *
|
66 | * #### Complexity
|
67 | * Linear.
|
68 | *
|
69 | * #### Example
|
70 | * ```typescript
|
71 | * import { findIndex } from '@lumino/algorithm';
|
72 | *
|
73 | * interface IAnimal { species: string, name: string };
|
74 | *
|
75 | * function isCat(value: IAnimal): boolean {
|
76 | * return value.species === 'cat';
|
77 | * }
|
78 | *
|
79 | * let data: IAnimal[] = [
|
80 | * { species: 'dog', name: 'spot' },
|
81 | * { species: 'cat', name: 'fluffy' },
|
82 | * { species: 'alligator', name: 'pocho' }
|
83 | * ];
|
84 | *
|
85 | * findIndex(data, isCat); // 1
|
86 | * ```
|
87 | */
|
88 | export function findIndex<T>(
|
89 | object: Iterable<T>,
|
90 | fn: (value: T, index: number) => boolean
|
91 | ): number {
|
92 | let index = 0;
|
93 | for (const value of object) {
|
94 | if (fn(value, index++)) {
|
95 | return index - 1;
|
96 | }
|
97 | }
|
98 | return -1;
|
99 | }
|
100 |
|
101 | /**
|
102 | * Find the minimum value in an iterable.
|
103 | *
|
104 | * @param object - The iterable object to search.
|
105 | *
|
106 | * @param fn - The 3-way comparison function to apply to the values.
|
107 | * It should return `< 0` if the first value is less than the second.
|
108 | * `0` if the values are equivalent, or `> 0` if the first value is
|
109 | * greater than the second.
|
110 | *
|
111 | * @returns The minimum value in the iterable. If multiple values are
|
112 | * equivalent to the minimum, the left-most value is returned. If
|
113 | * the iterable is empty, this returns `undefined`.
|
114 | *
|
115 | * #### Complexity
|
116 | * Linear.
|
117 | *
|
118 | * #### Example
|
119 | * ```typescript
|
120 | * import { min } from '@lumino/algorithm';
|
121 | *
|
122 | * function numberCmp(a: number, b: number): number {
|
123 | * return a - b;
|
124 | * }
|
125 | *
|
126 | * min([7, 4, 0, 3, 9, 4], numberCmp); // 0
|
127 | * ```
|
128 | */
|
129 | export function min<T>(
|
130 | object: Iterable<T>,
|
131 | fn: (first: T, second: T) => number
|
132 | ): T | undefined {
|
133 | let result: T | undefined = undefined;
|
134 | for (const value of object) {
|
135 | if (result === undefined) {
|
136 | result = value;
|
137 | continue;
|
138 | }
|
139 | if (fn(value, result) < 0) {
|
140 | result = value;
|
141 | }
|
142 | }
|
143 | return result;
|
144 | }
|
145 |
|
146 | /**
|
147 | * Find the maximum value in an iterable.
|
148 | *
|
149 | * @param object - The iterable object to search.
|
150 | *
|
151 | * @param fn - The 3-way comparison function to apply to the values.
|
152 | * It should return `< 0` if the first value is less than the second.
|
153 | * `0` if the values are equivalent, or `> 0` if the first value is
|
154 | * greater than the second.
|
155 | *
|
156 | * @returns The maximum value in the iterable. If multiple values are
|
157 | * equivalent to the maximum, the left-most value is returned. If
|
158 | * the iterable is empty, this returns `undefined`.
|
159 | *
|
160 | * #### Complexity
|
161 | * Linear.
|
162 | *
|
163 | * #### Example
|
164 | * ```typescript
|
165 | * import { max } from '@lumino/algorithm';
|
166 | *
|
167 | * function numberCmp(a: number, b: number): number {
|
168 | * return a - b;
|
169 | * }
|
170 | *
|
171 | * max([7, 4, 0, 3, 9, 4], numberCmp); // 9
|
172 | * ```
|
173 | */
|
174 | export function max<T>(
|
175 | object: Iterable<T>,
|
176 | fn: (first: T, second: T) => number
|
177 | ): T | undefined {
|
178 | let result: T | undefined = undefined;
|
179 | for (const value of object) {
|
180 | if (result === undefined) {
|
181 | result = value;
|
182 | continue;
|
183 | }
|
184 | if (fn(value, result) > 0) {
|
185 | result = value;
|
186 | }
|
187 | }
|
188 | return result;
|
189 | }
|
190 |
|
191 | /**
|
192 | * Find the minimum and maximum values in an iterable.
|
193 | *
|
194 | * @param object - The iterable object to search.
|
195 | *
|
196 | * @param fn - The 3-way comparison function to apply to the values.
|
197 | * It should return `< 0` if the first value is less than the second.
|
198 | * `0` if the values are equivalent, or `> 0` if the first value is
|
199 | * greater than the second.
|
200 | *
|
201 | * @returns A 2-tuple of the `[min, max]` values in the iterable. If
|
202 | * multiple values are equivalent, the left-most values are returned.
|
203 | * If the iterable is empty, this returns `undefined`.
|
204 | *
|
205 | * #### Complexity
|
206 | * Linear.
|
207 | *
|
208 | * #### Example
|
209 | * ```typescript
|
210 | * import { minmax } from '@lumino/algorithm';
|
211 | *
|
212 | * function numberCmp(a: number, b: number): number {
|
213 | * return a - b;
|
214 | * }
|
215 | *
|
216 | * minmax([7, 4, 0, 3, 9, 4], numberCmp); // [0, 9]
|
217 | * ```
|
218 | */
|
219 | export function minmax<T>(
|
220 | object: Iterable<T>,
|
221 | fn: (first: T, second: T) => number
|
222 | ): [T, T] | undefined {
|
223 | let empty = true;
|
224 | let vmin: T;
|
225 | let vmax: T;
|
226 | for (const value of object) {
|
227 | if (empty) {
|
228 | vmin = value;
|
229 | vmax = value;
|
230 | empty = false;
|
231 | } else if (fn(value, vmin!) < 0) {
|
232 | vmin = value;
|
233 | } else if (fn(value, vmax!) > 0) {
|
234 | vmax = value;
|
235 | }
|
236 | }
|
237 | return empty ? undefined : [vmin!, vmax!];
|
238 | }
|