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