|
| 1 | +import Repl from '@/repl/Repl.tsx'; |
| 2 | +import CodeLink from '@/mdx-components/CodeLink.tsx'; |
| 3 | + |
| 4 | +# Seq |
| 5 | + |
| 6 | +`Seq` describes a lazy operation, allowing them to efficiently chain |
| 7 | +use of all the higher-order collection methods (such as <CodeLink to="map" /> and <CodeLink to="filter" />) |
| 8 | +by not creating intermediate collections. |
| 9 | + |
| 10 | +<Signature code={`type Seq<K, V> extends Collection<K, V>`} /> |
| 11 | + |
| 12 | +**Seq is immutable** — Once a Seq is created, it cannot be |
| 13 | +changed, appended to, rearranged or otherwise modified. Instead, any |
| 14 | +mutative method called on a `Seq` will return a new `Seq`. |
| 15 | + |
| 16 | +**Seq is lazy** — `Seq` does as little work as necessary to respond to any |
| 17 | +method call. Values are often created during iteration, including implicit |
| 18 | +iteration when reducing or converting to a concrete data structure such as |
| 19 | +a <CodeLink to="../List" /> or JavaScript [`Array`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array). |
| 20 | + |
| 21 | +For example, the following performs no work, because the resulting |
| 22 | +`Seq`'s values are never iterated: |
| 23 | + |
| 24 | +```js |
| 25 | +import { Seq } from 'immutable'; |
| 26 | +const oddSquares = Seq([1, 2, 3, 4, 5, 6, 7, 8]) |
| 27 | + .filter((x) => x % 2 !== 0) |
| 28 | + .map((x) => x * x); |
| 29 | +``` |
| 30 | + |
| 31 | +Once the `Seq` is used, it performs only the work necessary. In this |
| 32 | +example, no intermediate arrays are ever created, filter is called three |
| 33 | +times, and map is only called once: |
| 34 | + |
| 35 | +```js |
| 36 | +oddSquares.get(1); // 9 |
| 37 | +``` |
| 38 | + |
| 39 | +Any collection can be converted to a lazy Seq with `Seq()`. |
| 40 | + |
| 41 | +```js |
| 42 | +import { Map } from 'immutable'; |
| 43 | + |
| 44 | +const map = Map({ a: 1, b: 2, c: 3 }); |
| 45 | +const lazySeq = Seq(map); |
| 46 | +``` |
| 47 | + |
| 48 | +`Seq` allows for the efficient chaining of operations, allowing for the |
| 49 | +expression of logic that can otherwise be very tedious: |
| 50 | + |
| 51 | +```js |
| 52 | +lazySeq |
| 53 | + .flip() |
| 54 | + .map((key) => key.toUpperCase()) |
| 55 | + .flip(); |
| 56 | +// Seq { A: 1, B: 1, C: 1 } |
| 57 | +``` |
| 58 | + |
| 59 | +As well as expressing logic that would otherwise seem memory or time |
| 60 | +limited, for example `Range` is a special kind of Lazy sequence. |
| 61 | + |
| 62 | +<Repl |
| 63 | + defaultValue={`Range(1, Infinity) |
| 64 | + .skip(1000) |
| 65 | + .map((n) => -n) |
| 66 | + .filter((n) => n % 2 === 0) |
| 67 | + .take(2) |
| 68 | + .reduce((r, n) => r * n, 1); |
| 69 | +`} |
| 70 | +/> |
| 71 | + |
| 72 | +Seq is often used to provide a rich collection API to JavaScript Object. |
| 73 | + |
| 74 | +<Repl |
| 75 | + defaultValue={`Seq({ x: 0, y: 1, z: 2 }) |
| 76 | + .map((v) => v * 2) |
| 77 | + .toObject();`} |
| 78 | +/> |
| 79 | + |
| 80 | +## Construction |
| 81 | + |
| 82 | +<MemberLabel label="Seq()" /> |
| 83 | + |
| 84 | +Creates a Seq. |
| 85 | + |
| 86 | +<Signature |
| 87 | + code={`function Seq<S extends Seq>(seq: S): S; |
| 88 | +function Seq(collection: Collection.Keyed<K, V>): Seq.Keyed<K, V>; |
| 89 | +function Seq(collection: Collection.Set<T>): Seq.Set<T>; |
| 90 | +function Seq(collection: Collection.Indexed<T> | Iterable<T> | ArrayLike<T>): Seq.Indexed<T>; |
| 91 | +function Seq(obj: { [key: string]: V }): Seq.Keyed<string, V>;`} |
| 92 | +/> |
| 93 | + |
| 94 | +Returns a particular kind of `Seq` based on the input. |
| 95 | + |
| 96 | + * If a `Seq`, that same `Seq`. |
| 97 | + * If an `Collection`, a `Seq` of the same kind (Keyed, Indexed, or Set). |
| 98 | + * If an Array-like, an `Seq.Indexed`. |
| 99 | + * If an Iterable Object, an `Seq.Indexed`. |
| 100 | + * If an Object, a `Seq.Keyed`. |
| 101 | + |
| 102 | +Note: An Iterator itself will be treated as an object, becoming a `Seq.Keyed`, |
| 103 | +which is usually not what you want. You should turn your Iterator Object into |
| 104 | +an iterable object by defining a Symbol.iterator (or @@iterator) method which |
| 105 | +returns `this`. |
| 106 | + |
| 107 | +Note: `Seq` is a conversion function and not a class, and does not use the |
| 108 | +`new` keyword during construction. |
| 109 | + |
| 110 | +## Static methods |
| 111 | + |
| 112 | +<MemberLabel label="isSeq()" /> |
| 113 | + |
| 114 | +<Signature |
| 115 | + code={`function isSeq(maybeSeq: unknown): maybeSeq is Seq.Indexed | Seq.Keyed | Seq.Set;`} |
| 116 | +/> |
| 117 | + |
| 118 | +## Members |
| 119 | + |
| 120 | +<MemberLabel label="size" /> |
| 121 | + |
| 122 | +Some Seqs can describe their size lazily. When this is the case, |
| 123 | +size will be an integer. Otherwise it will be undefined. |
| 124 | + |
| 125 | +<Signature code={`readonly size: number | undefined;`} /> |
| 126 | + |
| 127 | +For example, Seqs returned from <CodeLink to="map" /> or <CodeLink to="reverse" /> |
| 128 | +preserve the size of the original `Seq` while <CodeLink to="filter" /> does not. |
| 129 | + |
| 130 | +Note: <CodeLink to="../Range()" />, |
| 131 | + |
| 132 | +<CodeLink to="../Repeat()" /> and `Seq`s made from |
| 133 | +<CodeLink to="../List" />s and <CodeLink to="../Map" />s will always have a |
| 134 | +size. |
| 135 | + |
| 136 | +## Force evaluation |
| 137 | + |
| 138 | +<MemberLabel label="cacheResult()" /> |
| 139 | + |
| 140 | +Because Sequences are lazy and designed to be chained together, they do |
| 141 | +not cache their results. For example, this <CodeLink to="map" /> function is called a total |
| 142 | +of 6 times, as each `join` iterates the `Seq` of three values. |
| 143 | + |
| 144 | +<Signature code={`cacheResult(): this;`} /> |
| 145 | + |
| 146 | +```js |
| 147 | +var squares = Seq([1, 2, 3]).map((x) => x * x); |
| 148 | +squares.join() + squares.join(); |
| 149 | +``` |
| 150 | + |
| 151 | +If you know a `Seq` will be used multiple times, it may be more |
| 152 | +efficient to first cache it in memory. Here, the <CodeLink to="map" /> function is called |
| 153 | +only 3 times. |
| 154 | + |
| 155 | +```js |
| 156 | +var squares = Seq([1, 2, 3]) |
| 157 | + .map((x) => x * x) |
| 158 | + .cacheResult(); |
| 159 | +squares.join() + squares.join(); |
| 160 | +``` |
| 161 | + |
| 162 | +Use this method judiciously, as it must fully evaluate a `Seq` which can be |
| 163 | +a burden on memory and possibly performance. |
| 164 | + |
| 165 | +Note: after calling <CodeLink to="cacheResult" />, a `Seq` will always have a `size`. |
| 166 | + |
| 167 | +## Sequence algorithms |
| 168 | + |
| 169 | +<MemberLabel label="map()" /> |
| 170 | + |
| 171 | +Returns a new `Seq` with values passed through a |
| 172 | +`mapper` function. |
| 173 | + |
| 174 | +<Signature |
| 175 | + code={`map<M>(mapper: (value: V, key: K, iter: this) => M, context?: unknown): Seq<K, M>;`} |
| 176 | +/> |
| 177 | + |
| 178 | +<Repl defaultValue={`Seq([1, 2]).map((x) => 10 * x);`} /> |
| 179 | + |
| 180 | +Note: <CodeLink to="map" /> always returns a new instance, even if it produced the same |
| 181 | +value at every step. |
| 182 | +Note: used only for sets. |
| 183 | + |
| 184 | +<MemberLabel label="flatMap()" /> |
| 185 | + |
| 186 | +Flat-maps the `Seq`, returning a `Seq` of the same type. |
| 187 | + |
| 188 | +<Signature |
| 189 | + code={`flatMap<M>(mapper: (value: V, key: K, iter: this) => Iterable<M>, context?: unknown): Seq<K, M>;`} |
| 190 | +/> |
| 191 | + |
| 192 | +Similar to <CodeLink to="map" />(...).<CodeLink to="flatten" />(true). |
| 193 | + |
| 194 | +Note: Used only for sets. |
| 195 | + |
| 196 | +<MemberLabel label="filter()" /> |
| 197 | + |
| 198 | +Returns a new `Seq` with only the values for which the `predicate` |
| 199 | +function returns true. |
| 200 | + |
| 201 | +<Signature |
| 202 | + code={`filter(predicate: (value: V, key: K, iter: this) => unknown, context?: unknown): this;`} |
| 203 | +/> |
| 204 | + |
| 205 | +Note: <CodeLink to="filter" /> always returns a new instance, even if it results in |
| 206 | +not filtering out any values. |
| 207 | + |
| 208 | +<MemberLabel label="partition()" /> |
| 209 | + |
| 210 | +Returns a new `Seq` with the values for which the `predicate` function returns false and another for which is returns true. |
| 211 | + |
| 212 | +<Signature |
| 213 | + code={`partition<F extends V>( |
| 214 | + predicate: (this, value: V, key: K, iter) => value is F, |
| 215 | + context |
| 216 | + ): [Seq<K, V>, Seq<K, F>];`} |
| 217 | +/> |
| 218 | + |
| 219 | +<MemberLabel label="concat()" /> |
| 220 | + |
| 221 | +Returns a new `Seq` of the same type with other values and collection-like concatenated to this one. |
| 222 | + |
| 223 | +<Signature code={`concat(...valuesOrCollections): Seq;`} /> |
| 224 | + |
| 225 | +All entries will be present in the resulting `Seq`, even if they have the same key. |
| 226 | + |
| 227 | +<MemberLabel label="filterNot()" /> |
| 228 | + |
| 229 | +<MemberLabel label="reverse()" /> |
| 230 | + |
| 231 | +<MemberLabel label="sort()" /> |
| 232 | + |
| 233 | +<MemberLabel label="sortBy()" /> |
| 234 | + |
| 235 | +<MemberLabel label="groupBy()" /> |
| 236 | + |
| 237 | +## Value equality |
| 238 | + |
| 239 | +<MemberLabel label="equals()" /> |
| 240 | + |
| 241 | +<MemberLabel label="hashCode()" /> |
| 242 | + |
| 243 | +## Reading values |
| 244 | + |
| 245 | +<MemberLabel label="get()" /> |
| 246 | + |
| 247 | +<MemberLabel label="has()" /> |
| 248 | + |
| 249 | +<MemberLabel label="includes()" /> |
| 250 | + |
| 251 | +<MemberLabel label="first()" /> |
| 252 | + |
| 253 | +<MemberLabel label="last()" /> |
| 254 | + |
| 255 | +## Reading deep values |
| 256 | + |
| 257 | +<MemberLabel label="getIn()" /> |
| 258 | + |
| 259 | +<MemberLabel label="hasIn()" /> |
| 260 | + |
| 261 | +## Persistent changes |
| 262 | + |
| 263 | +<MemberLabel label="update()" /> |
| 264 | + |
| 265 | +## Conversion to JavaScript types |
| 266 | + |
| 267 | +<MemberLabel label="toJS()" /> |
| 268 | + |
| 269 | +<MemberLabel label="toJSON()" /> |
| 270 | + |
| 271 | +<MemberLabel label="toArray()" /> |
| 272 | + |
| 273 | +<MemberLabel label="toObject()" /> |
| 274 | + |
| 275 | +## Conversion to Collections |
| 276 | + |
| 277 | +<MemberLabel label="toMap()" /> |
| 278 | + |
| 279 | +<MemberLabel label="toOrderedMap()" /> |
| 280 | + |
| 281 | +<MemberLabel label="toSet()" /> |
| 282 | + |
| 283 | +<MemberLabel label="toOrderedSet()" /> |
| 284 | + |
| 285 | +<MemberLabel label="toList()" /> |
| 286 | + |
| 287 | +<MemberLabel label="toStack()" /> |
| 288 | + |
| 289 | +## Conversion to Seq |
| 290 | + |
| 291 | +<MemberLabel label="toSeq()" /> |
| 292 | + |
| 293 | +<MemberLabel label="toKeyedSeq()" /> |
| 294 | + |
| 295 | +<MemberLabel label="toIndexedSeq()" /> |
| 296 | + |
| 297 | +<MemberLabel label="toSetSeq()" /> |
| 298 | + |
| 299 | +## Iterators |
| 300 | + |
| 301 | +<MemberLabel label="keys()" /> |
| 302 | + |
| 303 | +<MemberLabel label="values()" /> |
| 304 | + |
| 305 | +<MemberLabel label="entries()" /> |
| 306 | + |
| 307 | +## Collections (Seq) |
| 308 | + |
| 309 | +<MemberLabel label="keySeq()" /> |
| 310 | + |
| 311 | +<MemberLabel label="valueSeq()" /> |
| 312 | + |
| 313 | +<MemberLabel label="entrySeq()" /> |
| 314 | + |
| 315 | +## Side effects |
| 316 | + |
| 317 | +<MemberLabel label="forEach()" /> |
| 318 | + |
| 319 | +## Creating subsets |
| 320 | + |
| 321 | +<MemberLabel label="slice()" /> |
| 322 | + |
| 323 | +<MemberLabel label="rest()" /> |
| 324 | + |
| 325 | +<MemberLabel label="butLast()" /> |
| 326 | + |
| 327 | +<MemberLabel label="skip()" /> |
| 328 | + |
| 329 | +<MemberLabel label="skipLast()" /> |
| 330 | + |
| 331 | +<MemberLabel label="skipWhile()" /> |
| 332 | + |
| 333 | +<MemberLabel label="skipUntil()" /> |
| 334 | + |
| 335 | +<MemberLabel label="take()" /> |
| 336 | + |
| 337 | +<MemberLabel label="takeLast()" /> |
| 338 | + |
| 339 | +<MemberLabel label="takeWhile" /> |
| 340 | + |
| 341 | +<MemberLabel label="takeUntil()" /> |
| 342 | + |
| 343 | +## Combination |
| 344 | + |
| 345 | +<MemberLabel label="flatten()" /> |
| 346 | + |
| 347 | +<MemberLabel label="reduce()" /> |
| 348 | + |
| 349 | +<MemberLabel label="reduceRight()" /> |
| 350 | + |
| 351 | +<MemberLabel label="every()" /> |
| 352 | + |
| 353 | +<MemberLabel label="some()" /> |
| 354 | + |
| 355 | +<MemberLabel label="join()" /> |
| 356 | + |
| 357 | +<MemberLabel label="isEmpty()" /> |
| 358 | + |
| 359 | +<MemberLabel label="count()" /> |
| 360 | + |
| 361 | +<MemberLabel label="countBy()" /> |
| 362 | + |
| 363 | +## Search for value |
| 364 | + |
| 365 | +<MemberLabel label="find()" /> |
| 366 | + |
| 367 | +<MemberLabel label="findLast()" /> |
| 368 | + |
| 369 | +<MemberLabel label="findEntry()" /> |
| 370 | + |
| 371 | +<MemberLabel label="findLastEntry()" /> |
| 372 | + |
| 373 | +<MemberLabel label="findKey()" /> |
| 374 | + |
| 375 | +<MemberLabel label="findLastKey()" /> |
| 376 | + |
| 377 | +<MemberLabel label="keyOf()" /> |
| 378 | + |
| 379 | +<MemberLabel label="lastKeyOf()" /> |
| 380 | + |
| 381 | +<MemberLabel label="max()" /> |
| 382 | + |
| 383 | +<MemberLabel label="maxBy()" /> |
| 384 | + |
| 385 | +<MemberLabel label="min()" /> |
| 386 | + |
| 387 | +<MemberLabel label="minBy()" /> |
| 388 | + |
| 389 | +## Comparison |
| 390 | + |
| 391 | +<MemberLabel label="isSubset()" /> |
| 392 | + |
| 393 | +<MemberLabel label="isSuperset()" /> |
0 commit comments