Add descending ranges and for-loop support
This commit is contained in:
1 parent
d8c53c500e
commit
f1003f5b95
15 files changed
+411
-98
No files matched your search
@@ -25,6 +25,23 @@ Exclusive end ranges are adopted from kotlin either:
|
||||
assert(4 in r)
|
||||
>>> void
|
||||
|
||||
Descending finite ranges are explicit too:
|
||||
|
||||
val r = 5 downTo 1
|
||||
assert(r.isDescending)
|
||||
assert(r.toList() == [5,4,3,2,1])
|
||||
>>> void
|
||||
|
||||
Use `downUntil` when the lower bound should be excluded:
|
||||
|
||||
val r = 5 downUntil 1
|
||||
assert(r.toList() == [5,4,3,2])
|
||||
assert(1 !in r)
|
||||
>>> void
|
||||
|
||||
This is explicit by design: `5..1` is not treated as a reverse range. It is an
|
||||
ordinary ascending range with no values in it when iterated.
|
||||
|
||||
In any case, we can test an object to belong to using `in` and `!in` and
|
||||
access limits:
|
||||
|
||||
@@ -73,6 +90,23 @@ but
|
||||
>>> 2
|
||||
>>> void
|
||||
|
||||
Descending ranges work in `for` loops exactly the same way:
|
||||
|
||||
for( i in 3 downTo 1 )
|
||||
println(i)
|
||||
>>> 3
|
||||
>>> 2
|
||||
>>> 1
|
||||
>>> void
|
||||
|
||||
And with an exclusive lower bound:
|
||||
|
||||
for( i in 3 downUntil 1 )
|
||||
println(i)
|
||||
>>> 3
|
||||
>>> 2
|
||||
>>> void
|
||||
|
||||
### Stepped ranges
|
||||
|
||||
Use `step` to change the iteration increment. The range bounds still define membership,
|
||||
@@ -80,9 +114,18 @@ so iteration ends when the next value is no longer in the range.
|
||||
|
||||
assert( [1,3,5] == (1..5 step 2).toList() )
|
||||
assert( [1,3] == (1..<5 step 2).toList() )
|
||||
assert( [5,3,1] == (5 downTo 1 step 2).toList() )
|
||||
assert( ['a','c','e'] == ('a'..'e' step 2).toList() )
|
||||
>>> void
|
||||
|
||||
Descending ranges still use a positive `step`; the direction comes from
|
||||
`downTo` / `downUntil`:
|
||||
|
||||
assert( ['e','c','a'] == ('e' downTo 'a' step 2).toList() )
|
||||
>>> void
|
||||
|
||||
A negative step with `downTo` / `downUntil` is invalid.
|
||||
|
||||
Real ranges require an explicit step:
|
||||
|
||||
assert( [0,0.25,0.5,0.75,1.0] == (0.0..1.0 step 0.25).toList() )
|
||||
@@ -119,6 +162,7 @@ Exclusive end char ranges are supported too:
|
||||
|-----------------|------------------------------|---------------|
|
||||
| contains(other) | used in `in` | Range, or Any |
|
||||
| isEndInclusive | true for '..' | Bool |
|
||||
| isDescending | true for `downTo`/`downUntil`| Bool |
|
||||
| isOpen | at any end | Bool |
|
||||
| isIntRange | both start and end are Int | Bool |
|
||||
| step | explicit iteration step | Any? |
|
||||
|
||||
@@ -50,8 +50,10 @@ Primary sources used: `lynglib/src/commonMain/kotlin/net/sergeych/lyng/{Parser,T
|
||||
- Range literals:
|
||||
- inclusive: `a..b`
|
||||
- exclusive end: `a..<b`
|
||||
- descending inclusive: `a downTo b`
|
||||
- descending exclusive end: `a downUntil b`
|
||||
- open-ended forms are supported (`a..`, `..b`, `..`).
|
||||
- optional step: `a..b step 2`
|
||||
- optional step: `a..b step 2`, `a downTo b step 2`
|
||||
- Lambda literal:
|
||||
- with params: `{ x, y -> x + y }`
|
||||
- implicit `it`: `{ it + 1 }`
|
||||
|
||||
@@ -1359,6 +1359,41 @@ size and index access, like lists:
|
||||
"total letters: "+letters
|
||||
>>> "total letters: 10"
|
||||
|
||||
When you need a counting loop that goes backwards, use an explicit descending
|
||||
range:
|
||||
|
||||
var sum = 0
|
||||
for( i in 5 downTo 1 ) {
|
||||
sum += i
|
||||
}
|
||||
sum
|
||||
>>> 15
|
||||
|
||||
If the lower bound should be excluded, use `downUntil`:
|
||||
|
||||
val xs = []
|
||||
for( i in 5 downUntil 1 ) {
|
||||
xs.add(i)
|
||||
}
|
||||
xs
|
||||
>>> [5,4,3,2]
|
||||
|
||||
This is intentionally explicit: `5..1` is an empty ascending range, not an
|
||||
implicit reverse loop.
|
||||
|
||||
Descending loops also support `step`:
|
||||
|
||||
val xs = []
|
||||
for( i in 10 downTo 1 step 3 ) {
|
||||
xs.add(i)
|
||||
}
|
||||
xs
|
||||
>>> [10,7,4,1]
|
||||
|
||||
For descending ranges, `step` stays positive. The direction comes from
|
||||
`downTo` / `downUntil`, so `10 downTo 1 step 3` is valid, while
|
||||
`10 downTo 1 step -3` is an error.
|
||||
|
||||
For loop support breaks the same as while loops above:
|
||||
|
||||
fun search(haystack, needle) {
|
||||
@@ -1488,6 +1523,14 @@ It could be open and closed:
|
||||
assert( 5 !in (1..<5) )
|
||||
>>> void
|
||||
|
||||
Descending ranges are explicit too:
|
||||
|
||||
(5 downTo 1).toList()
|
||||
>>> [5,4,3,2,1]
|
||||
|
||||
(5 downUntil 1).toList()
|
||||
>>> [5,4,3,2]
|
||||
|
||||
Ranges could be inside other ranges:
|
||||
|
||||
assert( (2..3) in (1..10) )
|
||||
@@ -1505,6 +1548,14 @@ and you can use ranges in for-loops:
|
||||
>>> b
|
||||
>>> void
|
||||
|
||||
Descending character ranges work the same way:
|
||||
|
||||
for( ch in 'e' downTo 'a' step 2 ) println(ch)
|
||||
>>> e
|
||||
>>> c
|
||||
>>> a
|
||||
>>> void
|
||||
|
||||
See [Ranges](Range.md) for detailed documentation on it.
|
||||
|
||||
# Time routines
|
||||
|
||||
Reference in new issue
Block a user