From 5586e027eacf1c0e47a6ee56d0a17e3fbffd8df0 Mon Sep 17 00:00:00 2001 From: sergeych Date: Wed, 24 Dec 2025 18:56:30 +0100 Subject: [PATCH] more stdlib and docs --- docs/Iterable.md | 76 ++++++++++++++++++--- docs/List.md | 3 +- lynglib/src/commonTest/kotlin/StdlibTest.kt | 7 ++ lynglib/stdlib/lyng/root.lyng | 27 ++++++-- 4 files changed, 98 insertions(+), 15 deletions(-) diff --git a/docs/Iterable.md b/docs/Iterable.md index 8a992ff..ba2f51a 100644 --- a/docs/Iterable.md +++ b/docs/Iterable.md @@ -55,7 +55,7 @@ Here is the sample: assertEquals( (1..3).joinToString { it * 10 }, "10 20 30") >>> void -## `sum` and `sumBy` +## `sum` and `sumOf` These, again, does the thing: @@ -68,17 +68,62 @@ These, again, does the thing: >>> void -## map and mapNotNull +## map, filter and their variations -Used to transform either the whole iterable stream or also skipping som elements from it: +Used to transform or filter the whole iterable stream: val source = [1,2,3,4] - // transform every element to string or null: - assertEquals(["n1", "n2", null, "n4"], source.map { if( it == 3 ) null else "n"+it } ) - // transform every element to stirng, skipping 3: + // map: transform every element to something else + assertEquals(["n1", "n2", "n3", "n4"], source.map { "n"+it } ) + + // filter: keep only elements matching the predicate + assertEquals([2, 4], source.filter { it % 2 == 0 } ) + + // count: count elements matching the predicate + assertEquals(2, source.count { it % 2 == 0 } ) + + // mapNotNull: transform every element, skipping null results: assertEquals(["n1", "n2", "n4"], source.mapNotNull { if( it == 3 ) null else "n"+it } ) + // filterNotNull: skip all null elements: + assertEquals([1, 2, 4], [1, 2, null, 4].filterNotNull()) + + >>> void + +You can also use flow variations that return a cold `Flow` instead of a `List`, which is useful for large or infinite sequences: + + val source = [1, 2, 3, 4] + + // filterFlow: returns a Flow of filtered elements + assert( source.filterFlow { it % 2 == 0 } is Flow ) + + // filterFlowNotNull: returns a Flow of non-null elements + assert( [1, null, 2].filterFlowNotNull() is Flow ) + + >>> void + +## minOf and maxOf + +Find the minimum or maximum value of a function applied to each element: + + val source = ["abc", "de", "fghi"] + assertEquals(2, source.minOf { it.length }) + assertEquals(4, source.maxOf { it.length }) + >>> void + +## flatten and flatMap + +Work with nested collections: + + val nested = [[1, 2], [3, 4]] + + // flatten: combine nested collections into one list + assertEquals([1, 2, 3, 4], nested.flatten()) + + // flatMap: map each element to a collection and flatten the result + assertEquals([1, 10, 2, 20], [1, 2].flatMap { [it, it*10] }) + >>> void ## findFirst and findFirstOrNull @@ -108,10 +153,21 @@ Search for the first element that satisfies the given predicate: | isEmpty() | check iterable is empty | | forEach(f) | call f for each element | | toMap() | create a map from list of key-value pairs (arrays of 2 items or like) | +| any(p) | true if any element matches predicate `p` | +| all(p) | true if all elements match predicate `p` | | map(f) | create a list of values returned by `f` called for each element of the iterable | | indexOf(i) | return index if the first encounter of i or a negative value if not found | | associateBy(kf) | create a map where keys are returned by kf that will be called for each element | -| findFirst(p) | return first element matching predicate `p` or throw (1) | +| filter(p) | create a list of elements matching predicate `p` | +| count(p) | count elements matching predicate `p` | +| filterFlow(p) | create a [Flow] of elements matching predicate `p` | +| filterNotNull() | create a list of non-null elements | +| filterFlowNotNull() | create a [Flow] of non-null elements | +| minOf(f) | return minimum value of `f` applied to elements | +| maxOf(f) | return maximum value of `f` applied to elements | +| flatten() | flatten nested collections into a single [List] | +| flatMap(f) | map each element with `f` and flatten results into a [List] | +| findFirst(p) | return first element matching predicate `p` or throw (1) | | findFirstOrNull(p) | return first element matching predicate `p` or `null` | | first | first element (1) | | last | last element (1) | @@ -120,13 +176,13 @@ Search for the first element that satisfies the given predicate: | drop(n) | return new [Iterable] without first n elements | | dropLast(n) | return new [Iterable] without last n elements | | sum() | return sum of the collection applying `+` to its elements (3) | -| sumOf(predicate) | sum of the modified collection items (3) | +| sumOf(f) | sum of the modified collection items (3) | | sorted() | return [List] with collection items sorted naturally | | sortedWith(comparator) | sort using a comparator that compares elements (1) | | sortedBy(predicate) | sort by comparing results of the predicate function | | joinToString(s,t) | convert iterable to string, see (2) | | reversed() | create a list containing items from this in reverse order | -| shuffled() | create a listof shiffled elements | +| shuffled() | create a list of shuffled elements | (1) :: throws `NoSuchElementException` if there is no such element @@ -156,6 +212,8 @@ For high-performance Kotlin-side interop and custom iterable implementation deta [List]: List.md +[Flow]: parallelism.md#flow + [Range]: Range.md [Set]: Set.md diff --git a/docs/List.md b/docs/List.md index 0631ffd..e007f30 100644 --- a/docs/List.md +++ b/docs/List.md @@ -158,7 +158,8 @@ List could be sorted in place, just like [Collection] provide sorted copies, in | `sort()` | in-place sort, natural order | void | | `sortBy(predicate)` | in-place sort bu `predicate` call result (3) | void | | `sortWith(comparator)` | in-place sort using `comarator` function (4) | void | -| `shiffle()` | in-place shiffle contents | | +| `shuffle()` | in-place shuffle contents | | +| `toString()` | string representation like `[a,b,c]` | | (1) : optimized implementation that override `Array` one diff --git a/lynglib/src/commonTest/kotlin/StdlibTest.kt b/lynglib/src/commonTest/kotlin/StdlibTest.kt index 3e07f6a..43523c2 100644 --- a/lynglib/src/commonTest/kotlin/StdlibTest.kt +++ b/lynglib/src/commonTest/kotlin/StdlibTest.kt @@ -106,4 +106,11 @@ class StdlibTest { assertEquals([1,2,3,4,5,6], [1,3,5].flatMap { [it,it+1] }.toList() ) """) } + + @Test + fun testCount() = runTest { + eval(""" + assertEquals(5, (1..10).toList().count { it % 2 == 1 } ) + """) + } } \ No newline at end of file diff --git a/lynglib/stdlib/lyng/root.lyng b/lynglib/stdlib/lyng/root.lyng index 91e934a..5289520 100644 --- a/lynglib/stdlib/lyng/root.lyng +++ b/lynglib/stdlib/lyng/root.lyng @@ -15,8 +15,10 @@ fun cached(builder) { value } } -/* Filter elements of this iterable using the provided predicate. */ -fun Iterable.filterFlow(predicate) { +/* Filter elements of this iterable using the provided predicate and provide a flow + of results. Coudl be used to map infinte flows, etc. +*/ +fun Iterable.filterFlow(predicate): Flow { val list = this flow { for( item in list ) { @@ -27,6 +29,9 @@ fun Iterable.filterFlow(predicate) { } } +/* +Filter this iterable and return List of elements +*/ fun Iterable.filter(predicate) { val result = [] for( item in this ) if( predicate(item) ) result.add(item) @@ -34,14 +39,26 @@ fun Iterable.filter(predicate) { } /* -filter out all null elements from this collection (Iterable); collection of +Count all items in this iterable for which predicate return true +*/ +fun Iterable.count(predicate): Int { + var hits = 0 + this.forEach { + if( predicate(it) ) hits++ + } + hits +} +/* +filter out all null elements from this collection (Iterable); flow of non-null elements is returned */ -fun Iterable.filterFlowNotNull() { +fun Iterable.filterFlowNotNull(): Flow { filterFlow { it != null } } -fun Iterable.filterNotNull() { +/* Filter non-null elements and collect them into a List +*/ +fun Iterable.filterNotNull(): List { filter { it != null } }