UNPKG

5.98 kBPlain TextView Raw
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 */
43export 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 */
88export 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 */
129export 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 */
174export 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 */
219export 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}