sorted* moved to Iterable
in-place List sort v0.8.15-SNAPSHOT
This commit is contained in:
parent
a5e51a3f90
commit
0ec0ed96ee
@ -6,6 +6,12 @@ Is a [Iterable] with known `size`, a finite [Iterable]:
|
||||
val size
|
||||
}
|
||||
|
||||
| name | description |
|
||||
|------------------------|------------------------------------------------------|
|
||||
|
||||
(1)
|
||||
: `comparator(a,b)` should return -1 if `a < b`, +1 if `a > b` or zero.
|
||||
|
||||
See [List], [Set] and [Iterable]
|
||||
|
||||
[Iterable]: Iterable.md
|
||||
|
@ -1,9 +1,13 @@
|
||||
# Iterable interface
|
||||
|
||||
The interface for anything that can be iterated, e.g. finite or infinite ordered set of data that can be accessed sequentially. Almost any data container in `Lyng` implements it: `List`, `Set`, `Buffer`, `RingBuffer`, `BitBuffer`, `Range` and many others are `Iterable`, also `Collection` and `Array` interfaces inherit it.
|
||||
The interface for anything that can be iterated, e.g. finite or infinite ordered set of data that can be accessed
|
||||
sequentially. Almost any data container in `Lyng` implements it: `List`, `Set`, `Buffer`, `RingBuffer`, `BitBuffer`,
|
||||
`Range` and many others are `Iterable`, also `Collection` and `Array` interfaces inherit it.
|
||||
|
||||
`Map` and `String` have `Iterable` members to access its contents too.
|
||||
|
||||
Please see also [Collection] interface: many iterables are also collections, and it adds important features.
|
||||
|
||||
## Definition:
|
||||
|
||||
Iterable is a class that provides function that creates _the iterator_:
|
||||
@ -23,7 +27,8 @@ Iterator itself is a simple interface that should provide only to method:
|
||||
|
||||
Just remember at this stage typed declarations are not yet supported.
|
||||
|
||||
Having `Iterable` in base classes allows to use it in for loop. Also, each `Iterable` has some utility functions available, for example
|
||||
Having `Iterable` in base classes allows to use it in for loop. Also, each `Iterable` has some utility functions
|
||||
available, for example
|
||||
|
||||
val r = 1..10 // Range is Iterable!
|
||||
assertEquals( [9,10], r.takeLast(2).toList() )
|
||||
@ -34,12 +39,13 @@ Having `Iterable` in base classes allows to use it in for loop. Also, each `Iter
|
||||
|
||||
## joinToString
|
||||
|
||||
This methods convert any iterable to a string joining string representation of each element, optionally transforming it and joining using specified suffix.
|
||||
This methods convert any iterable to a string joining string representation of each element, optionally transforming it
|
||||
and joining using specified suffix.
|
||||
|
||||
Iterable.joinToString(suffux=' ', transform=null)
|
||||
|
||||
- if `Iterable` `isEmpty`, the empty string `""` is returned.
|
||||
- `suffix` is inserted between items when there are more than one.
|
||||
- `suffix` is inserted between items when there are more than one.
|
||||
- `transform` of specified is applied to each element, otherwise its `toString()` method is used.
|
||||
|
||||
Here is the sample:
|
||||
@ -49,34 +55,56 @@ Here is the sample:
|
||||
assertEquals( (1..3).joinToString { it * 10 }, "10 20 30")
|
||||
>>> void
|
||||
|
||||
## `sum` and `sumBy`
|
||||
|
||||
These, again, does the thing:
|
||||
|
||||
assertEquals( 6, [1,2,3].sum() )
|
||||
assertEquals( 12, [1,2,3].sumOf { it*2 } )
|
||||
|
||||
// sum of empty collections is null:
|
||||
assertEquals( null, [].sum() )
|
||||
assertEquals( null, [].sumOf { 2*it } )
|
||||
|
||||
>>> void
|
||||
|
||||
## Instance methods:
|
||||
|
||||
|
||||
| fun/method | description |
|
||||
|-------------------|---------------------------------------------------------------------------|
|
||||
| toList() | create a list from iterable |
|
||||
| toSet() | create a set from iterable |
|
||||
| contains(i) | check that iterable contains `i` |
|
||||
| `i in iterator` | same as `contains(i)` |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| first | first element (1) |
|
||||
| last | last element (1) |
|
||||
| take(n) | return [Iterable] of up to n first elements |
|
||||
| taleLast(n) | return [Iterable] of up to n last elements |
|
||||
| drop(n) | return new [Iterable] without first n elements |
|
||||
| dropLast(n) | return new [Iterable] without last n elements |
|
||||
| joinToString(s,t) | convert iterable to string, see (2) |
|
||||
| fun/method | description |
|
||||
|------------------------|---------------------------------------------------------------------------------|
|
||||
| toList() | create a list from iterable |
|
||||
| toSet() | create a set from iterable |
|
||||
| contains(i) | check that iterable contains `i` |
|
||||
| `i in iterator` | same as `contains(i)` |
|
||||
| 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) |
|
||||
| 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 |
|
||||
| first | first element (1) |
|
||||
| last | last element (1) |
|
||||
| take(n) | return [Iterable] of up to n first elements |
|
||||
| taleLast(n) | return [Iterable] of up to n last elements |
|
||||
| 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) |
|
||||
| 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 |
|
||||
|
||||
(1)
|
||||
: throws `NoSuchElementException` if there is no such element
|
||||
: throws `NoSuchElementException` if there is no such element
|
||||
|
||||
(2)
|
||||
: `joinToString(suffix=" ",transform=null)`: suffix is inserted between items if there are more than one, trasnfom is optional function applied to each item that must return result string for an item, otherwise `item.toString()` is used.
|
||||
: `joinToString(suffix=" ",transform=null)`: suffix is inserted between items if there are more than one, trasnfom is
|
||||
optional function applied to each item that must return result string for an item, otherwise `item.toString()` is used.
|
||||
|
||||
(3)
|
||||
: sum of empty collection is `null`
|
||||
|
||||
fun Iterable.toList(): List
|
||||
fun Iterable.toSet(): Set
|
||||
@ -86,7 +114,6 @@ Here is the sample:
|
||||
fun Iterable.forEach(block: (Any?)->Void ): Void
|
||||
fun Iterable.map(block: (Any?)->Void ): List
|
||||
fun Iterable.associateBy( keyMaker: (Any?)->Any): Map
|
||||
|
||||
|
||||
## Abstract methods:
|
||||
|
||||
@ -102,7 +129,12 @@ Creates a list by iterating to the end. So, the Iterator should be finite to be
|
||||
|
||||
- [List], [Range], [Buffer](Buffer.md), [BitBuffer], [Buffer], [Set], [RingBuffer]
|
||||
|
||||
[Collection]: Collection.md
|
||||
|
||||
[List]: List.md
|
||||
|
||||
[Range]: Range.md
|
||||
|
||||
[Set]: Set.md
|
||||
|
||||
[RingBuffer]: RingBuffer.md
|
62
docs/List.md
62
docs/List.md
@ -92,22 +92,44 @@ Open end ranges remove head and tail elements:
|
||||
assert( [1, 2, 3] !== [1, 2, 3])
|
||||
>>> void
|
||||
|
||||
## In-place sort
|
||||
|
||||
List could be sorted in place, just like [Collection] provide sorted copies, in a very like way:
|
||||
|
||||
val l1 = [6,3,1,9]
|
||||
l1.sort()
|
||||
assertEquals( [1,3,6,9], l1)
|
||||
|
||||
l1.sortBy { -it }
|
||||
assertEquals( [1,3,6,9].reversed(), l1)
|
||||
|
||||
l1.sort() // 1 3 6 9
|
||||
l1.sortBy { it % 4 }
|
||||
// 1,3,6,9 gives, mod 4:
|
||||
// 1 3 2 1
|
||||
// we hope we got it also stable:
|
||||
assertEquals( [1,9,6,3], l1)
|
||||
>>> void
|
||||
|
||||
## Members
|
||||
|
||||
| name | meaning | type |
|
||||
|-------------------------------|---------------------------------------|-------------|
|
||||
| `size` | current size | Int |
|
||||
| `add(elements...)` | add one or more elements to the end | Any |
|
||||
| `insertAt(index,elements...)` | insert elements at position | Int, Any |
|
||||
| `removeAt(index)` | remove element at position | Int |
|
||||
| `remove(from,toNonInclusive)` | remove range from (incl) to (nonincl) | Int, Int |
|
||||
| `remove(Range)` | remove range | Range |
|
||||
| `removeLast()` | remove last element | |
|
||||
| `removeLast(n)` | remove n last elements | Int |
|
||||
| `contains(element)` | check the element is in the list (1) | |
|
||||
| `[index]` | get or set element at index | Int |
|
||||
| `[Range]` | get slice of the array (copy) | Range |
|
||||
| `+=` | append element(s) | List or Obj |
|
||||
| name | meaning | type |
|
||||
|-------------------------------|----------------------------------------------|-------------|
|
||||
| `size` | current size | Int |
|
||||
| `add(elements...)` | add one or more elements to the end | Any |
|
||||
| `insertAt(index,elements...)` | insert elements at position | Int, Any |
|
||||
| `removeAt(index)` | remove element at position | Int |
|
||||
| `remove(from,toNonInclusive)` | remove range from (incl) to (nonincl) | Int, Int |
|
||||
| `remove(Range)` | remove range | Range |
|
||||
| `removeLast()` | remove last element | |
|
||||
| `removeLast(n)` | remove n last elements | Int |
|
||||
| `contains(element)` | check the element is in the list (1) | |
|
||||
| `[index]` | get or set element at index | Int |
|
||||
| `[Range]` | get slice of the array (copy) | Range |
|
||||
| `+=` | append element(s) (2) | List or Obj |
|
||||
| `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 |
|
||||
|
||||
(1)
|
||||
: optimized implementation that override `Array` one
|
||||
@ -116,7 +138,16 @@ Open end ranges remove head and tail elements:
|
||||
: `+=` append either a single element, or all elements if the List or other Iterable
|
||||
instance is appended. If you want to append an Iterable object itself, use `add` instead.
|
||||
|
||||
It inherits from [Iterable] too.
|
||||
(3)
|
||||
: predicate is called on each element, and the returned values are used to sort in natural
|
||||
order, e.g. is same as `list.sortWith { a,b -> predicate(a) <=> predicate(b) }`
|
||||
|
||||
(4)
|
||||
: comparator callable takes tho arguments and must return: negative value when first is less,
|
||||
positive if first is greater, and zero if they are equal. For example, the equvalent comparator
|
||||
for `sort()` will be `sort { a, b -> a <=> b }
|
||||
|
||||
It inherits from [Iterable] too and thus all iterable methods are applicable to any list.
|
||||
|
||||
## Member inherited from Array
|
||||
|
||||
@ -134,4 +165,5 @@ It inherits from [Iterable] too.
|
||||
|
||||
|
||||
[Range]: Range.md
|
||||
|
||||
[Iterable]: Iterable.md
|
@ -764,15 +764,15 @@ thrown.
|
||||
|
||||
Typical builtin types that are containers (e.g. support `contains`):
|
||||
|
||||
| class | notes |
|
||||
|------------|------------------------------------------------|
|
||||
| Collection | contains an element (1) |
|
||||
| Array | faster maybe that Collection's |
|
||||
| List | faster than Array's |
|
||||
| String | character in string or substring in string (3) |
|
||||
| Range | object is included in the range (2) |
|
||||
| Buffer | byte is in buffer |
|
||||
| RingBuffer | object is in buffer |
|
||||
| class | notes |
|
||||
|--------------|------------------------------------------------|
|
||||
| [Collection] | contains an element (1) |
|
||||
| Array | faster maybe that Collection's |
|
||||
| List | faster than Array's |
|
||||
| String | character in string or substring in string (3) |
|
||||
| Range | object is included in the range (2) |
|
||||
| Buffer | byte is in buffer |
|
||||
| RingBuffer | object is in buffer |
|
||||
|
||||
(1)
|
||||
: Iterable is not the container as it can be infinite
|
||||
@ -1361,4 +1361,6 @@ See [math functions](math.md). Other general purpose functions are:
|
||||
|
||||
[parallelism]: parallelism.md
|
||||
|
||||
[RingBuffer]: RingBuffer.md
|
||||
[RingBuffer]: RingBuffer.md
|
||||
|
||||
[Collection]: Collection.md
|
@ -21,7 +21,7 @@ import org.jetbrains.kotlin.gradle.ExperimentalWasmDsl
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
|
||||
group = "net.sergeych"
|
||||
version = "0.8.14-SNAPSHOT"
|
||||
version = "0.8.15-SNAPSHOT"
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
|
@ -18,8 +18,8 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
/**
|
||||
* Collection is an iterator with `size`]
|
||||
* Collection is an iterator with `size`
|
||||
*/
|
||||
val ObjCollection = ObjClass("Collection", ObjIterable).apply {
|
||||
}
|
||||
|
||||
}
|
@ -119,12 +119,6 @@ val ObjIterable by lazy {
|
||||
ObjList(result)
|
||||
}
|
||||
|
||||
// addFn("drop" ) {
|
||||
// var n = requireOnlyArg<ObjInt>().value.toInt()
|
||||
// if( n < 0 ) raiseIllegalArgument("drop($n): should be positive")
|
||||
// val it = callMethod<>()
|
||||
// }
|
||||
|
||||
addFn("isEmpty") {
|
||||
ObjBool(
|
||||
thisObj.invokeInstanceMethod(this, "iterator")
|
||||
@ -132,5 +126,21 @@ val ObjIterable by lazy {
|
||||
.not()
|
||||
)
|
||||
}
|
||||
|
||||
addFn("sortedWith") {
|
||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
||||
val comparator = requireOnlyArg<Statement>()
|
||||
list.quicksort { a, b ->
|
||||
comparator.call(this, a, b).toInt()
|
||||
}
|
||||
list
|
||||
}
|
||||
|
||||
addFn("reversed") {
|
||||
val list = thisObj.callMethod<ObjList>(this, "toList")
|
||||
list.list.reverse()
|
||||
list
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -18,6 +18,7 @@
|
||||
package net.sergeych.lyng.obj
|
||||
|
||||
import net.sergeych.lyng.Scope
|
||||
import net.sergeych.lyng.Statement
|
||||
import net.sergeych.lyng.statement
|
||||
import net.sergeych.lynon.LynonDecoder
|
||||
import net.sergeych.lynon.LynonEncoder
|
||||
@ -127,6 +128,33 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
return list.map { it.toKotlin(scope) }
|
||||
}
|
||||
|
||||
suspend fun quicksort(compare: suspend (Obj, Obj) -> Int) = quicksort(compare, 0, list.size - 1)
|
||||
|
||||
suspend fun quicksort(compare: suspend (Obj, Obj) -> Int, left: Int, right: Int) {
|
||||
if (left >= right) return
|
||||
var i = left
|
||||
var j = right
|
||||
val pivot = list[left]
|
||||
while (i < j) {
|
||||
// Сдвигаем j влево, пока элемент меньше pivot
|
||||
while (i < j && compare(list[j], pivot) >= 0) {
|
||||
j--
|
||||
}
|
||||
// Сдвигаем i вправо, пока элемент больше pivot
|
||||
while (i < j && compare(list[i], pivot) <= 0) {
|
||||
i++
|
||||
}
|
||||
if (i < j) {
|
||||
list.swap(i, j)
|
||||
}
|
||||
}
|
||||
// После завершения i == j, ставим pivot на своё место
|
||||
list.swap(left, i)
|
||||
// Рекурсивно сортируем левую и правую части
|
||||
quicksort(compare, left, i - 1)
|
||||
quicksort(compare, i + 1, right)
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
// check?
|
||||
return list.hashCode()
|
||||
@ -235,8 +263,23 @@ class ObjList(val list: MutableList<Obj> = mutableListOf()) : Obj() {
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
addFn("sortWith") {
|
||||
val comparator = requireOnlyArg<Statement>()
|
||||
thisAs<ObjList>().quicksort { a, b -> comparator.call(this, a, b).toInt() }
|
||||
ObjVoid
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Расширение MutableList для удобного обмена элементами
|
||||
fun <T>MutableList<T>.swap(i: Int, j: Int) {
|
||||
if (i in indices && j in indices) {
|
||||
val temp = this[i]
|
||||
this[i] = this[j]
|
||||
this[j] = temp
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -103,10 +103,46 @@ fun Iterable.all(predicate): Bool {
|
||||
!any { !predicate(it) }
|
||||
}
|
||||
|
||||
fun Iterable.sum() {
|
||||
val i = iterator()
|
||||
if( i.hasNext() ) {
|
||||
var result = i.next()
|
||||
while( i.hasNext() ) result += i.next()
|
||||
result
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
fun Iterable.sumOf(f) {
|
||||
val i = iterator()
|
||||
if( i.hasNext() ) {
|
||||
var result = f(i.next())
|
||||
while( i.hasNext() ) result += f(i.next())
|
||||
result
|
||||
}
|
||||
else null
|
||||
}
|
||||
|
||||
fun Iterable.sorted() {
|
||||
sortedWith { a, b -> a <=> b }
|
||||
}
|
||||
|
||||
fun Iterable.sortedBy(predicate) {
|
||||
sortedWith { a, b -> predicate(a) <=> predicate(b) }
|
||||
}
|
||||
|
||||
fun List.toString() {
|
||||
"[" + joinToString(",") + "]"
|
||||
}
|
||||
|
||||
fun List.sortBy(predicate) {
|
||||
sortWith { a, b -> predicate(a) <=> predicate(b) }
|
||||
}
|
||||
|
||||
fun List.sort() {
|
||||
sortWith { a, b -> a <=> b }
|
||||
}
|
||||
|
||||
class StackTraceEntry(
|
||||
val sourceName: String,
|
||||
val line: Int,
|
||||
@ -124,6 +160,7 @@ fun Exception.printStackTrace() {
|
||||
println("\tat "+entry)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
""".trimIndent()
|
||||
|
||||
|
@ -3095,10 +3095,12 @@ class ScriptTest {
|
||||
|
||||
@Test
|
||||
fun testOverridenListToString() = runTest {
|
||||
eval("""
|
||||
eval(
|
||||
"""
|
||||
val x = [1,2,3]
|
||||
assertEquals( "[1,2,3]", x.toString() )
|
||||
""".trimIndent())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -3131,7 +3133,8 @@ class ScriptTest {
|
||||
|
||||
@Test
|
||||
fun testThisInClosure() = runTest {
|
||||
eval("""
|
||||
eval(
|
||||
"""
|
||||
fun Iterable.sum2by(f) {
|
||||
var acc = null
|
||||
for( x in this ) {
|
||||
@ -3147,12 +3150,14 @@ class ScriptTest {
|
||||
}
|
||||
}
|
||||
assertEquals(60, T([1,2,3], 10).sum())
|
||||
""".trimIndent())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testThisInFlowClosure() = runTest {
|
||||
eval("""
|
||||
eval(
|
||||
"""
|
||||
class T(val coll, val factor) {
|
||||
fun seq() {
|
||||
flow {
|
||||
@ -3163,7 +3168,50 @@ class ScriptTest {
|
||||
}
|
||||
}
|
||||
assertEquals([10,20,30], T([1,2,3], 10).seq().toList())
|
||||
""".trimIndent())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSum() = runTest {
|
||||
eval(
|
||||
"""
|
||||
assertEquals(1, [1].sum())
|
||||
assertEquals(null, [].sum())
|
||||
assertEquals(6, [1,2,3].sum())
|
||||
assertEquals(30, [3].sumOf { it * 10 })
|
||||
assertEquals(null, [].sumOf { it * 10 })
|
||||
assertEquals(60, [1,2,3].sumOf { it * 10 })
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSort() = runTest {
|
||||
eval("""
|
||||
val coll = [5,4,1,7]
|
||||
assertEquals( [1,4,5,7], coll.sortedWith { a,b -> a <=> b })
|
||||
assertEquals( [1,4,5,7], coll.sorted())
|
||||
assertEquals( [7,5,4,1], coll.sortedBy { -it })
|
||||
assertEquals( [1,4,5,7], coll.sortedBy { -it }.reversed())
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testListSortInPlace() = runTest {
|
||||
eval("""
|
||||
val l1 = [6,3,1,9]
|
||||
l1.sort()
|
||||
assertEquals( [1,3,6,9], l1)
|
||||
l1.sortBy { -it }
|
||||
assertEquals( [1,3,6,9].reversed(), l1)
|
||||
l1.sort()
|
||||
l1.sortBy { it % 4 }
|
||||
// 1,3,6,9
|
||||
// 1 3 2 1
|
||||
// we hope we got it also stable:
|
||||
assertEquals( [1,9,6,3], l1)
|
||||
""")
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user