If a Slice
instance with stride
is used, we can save memory when performing forEach
, map
, or etc.
x[stride(from: 0, to: 100000, by: 2)].forEach {...}
let y = x[stride(from: 0, to: 100000, by: 2)].map {...}
If a Slice
instance with stride
is used, we can save memory when performing forEach
, map
, or etc.
x[stride(from: 0, to: 100000, by: 2)].forEach {...}
let y = x[stride(from: 0, to: 100000, by: 2)].map {...}
.+=
or ..+=
might be better than ..+
and .++
.
for x in -10 ..+= 4 {
print(x)
break
}
Array(10 ..+= -4 ... -10)
Array(-10 ..+= 4 ..! 10)
I wonder how many readers reacted on the fact that your statement is making the invalid assumption that "any sequence" is multi-pass, breaking the (current) semantic requirements of Sequence
.
This is a very common mistake (that I myself use(d) to make). After I realized this, I started this thread which might be an Interesting read.
EDIT: No, I was wrong, your subscript will work as expected even with a single-pass sequence.
Is it? It appears to only be doing a single pass over seq
to me (the for-in
loop). What am I missing?
You are right, I misread the code (It's almost as if I want to see everyone making these mistakes! ). Edited my post.
As @Chris_Lattner3 said for the /
operator, the %
operator would also be not preferable.
Would it be possible to just use a contextual keyword "by" for this?
let x = 0...100 by 5
It feels very natural to me.
I think the keyword by
should be the last option.
%%
might be an option for the stride operator.
for i in -10 %% 4 {...}
for i in -10 %% 4 ..! 10 {...}
If you try the %%
operator, replace the corresponding part of the previous implementation with the following code:
precedencegroup StrideFormationPrecedence {
higherThan: RangeFormationPrecedence
lowerThan: AdditionPrecedence
}
infix operator %% : StrideFormationPrecedence
infix operator ..! : RangeFormationPrecedence
func %% <T: Strideable>(start: T, step: T.Stride) -> Stride<T> {
return stride(from: start, by: step)
}
for i in -10 %% 4 ... {...}
is beter than it, because the range expression ...
is included. But, I cloud not implement this postfix operator ...
. Please help me!
I implemented the stride operator %%
to create StrideTo
from Range
, StrideThrough
from ClosedRange
, and StrideFrom
from CountablePartialRangeFrom
, PartialRangeUpTo
, and PartialRangeThrough
. The StrideFrom
structure is almost the same as the Stride
structure introduced by @Alexandre_Lopoukhine.
For example,
Array(-10..<10%%4) // [-10, -6, -2, 2, 6]
Array(-10...10%%4) // [-10, -6, -2, 2, 6, 10]
for i in (-10)... %% 4 {
print(i) // -10 -6 -2 2 6 10
if i >= 10 { break }
}
for i in ..<10 %% -4 {
print(i) // 6 2 -2 -6 -10
if i <= -10 { break }
}
for i in ...10 %% -4 {
print(i) // 10 6 2 -2 -6 -10
if i <= -10 { break }
}
I spent some time playing around with this. I found that it feels less readable than using stride
directly, for example:
// Clear, understandable, built using recognition
stride(from: 1, through: 10, by: 3)
// Depends more on interpreting intent
(1 ... 10) / 3
// Does this return (1/3, 2/3, 3/3, ...)?
// Does this return 1, 4, 7?
// Does this return 1..<4, 4..<7, 7..<10? or 1..<4, 4..<7, 7..<10, 10...10?
The answer is the first (because you state it wraps stride) but in doing so, it removes clarity to achieve concision and forces the use of parentheses.
Thank you for bringing up this topic. It gave me a lot to think about.
I fixed the %%
operator for the half-open range stride with a negative stride.
- return stride(from: left.upperBound, to: left.lowerBound, by: right)
+ return stride(from: left.upperBound.advanced(by: right), to: left.lowerBound.advanced(by: right), by: right)
Upon this fix, the reverse stride of the half-open range behaves as you expect:
Array(-10..<10 %% -4) // [6, 2, -2, -6, -10]
The generic structure Array
has the instance property:
var indices: CountableRange<Int> { get }
To create the stride
range from this indices
, I added the stride operators %%
for CountableRange
as well as CountableClosedRange
.
For example:
let a = (0..<100).map { Double($0) }
for i in a.indices %% 20 { print(a[i]) } // 0.0 20.0 40.0 60.0 80.0
for i in a.indices %% -20 { print(a[i]) } // 80.0 60.0 40.0 20.0 0.0
let a = (0...100).map { Double($0) }
let range = CountableClosedRange(a.indices)
for i in range %% 20 { print(a[i]) } // 0.0 20.0 40.0 60.0 80.0 100.0
for i in range %% -20 { print(a[i]) } // 100.0 80.0 60.0 40.0 20.0 0.0
I am sorry. This fix is wrong. I fixed as the stride starts from the last element of the half-open range:
- return stride(from: left.upperBound.advanced(by: right), to: left.lowerBound.advanced(by: right), by: right)
+ return stride(from: left.upperBound.advanced(by: -1), to: left.lowerBound.advanced(by: -1), by: right)
For example:
Array(-10..<10 %% -4) // [9, 5, 1, -3, -7]
let a = (0..<100).map { Double($0) }
for i in a.indices %% -20 {
print(a[i]) // 99.0 79.0 59.0 39.0 19.0
}
For the PartialRangeUpTo
range, I also fixed as the stride starts from the last element of the range:
- return stride(from: left.upperBound.advanced(by: right), by: right)
+ return stride(from: left.upperBound.advanced(by: -1), by: right)
For example:
for i in ..<10 %% -4 {
print(i) // 9 5 1 -3 -7 -11
if i <= -10 { break }
}
Hi @Tony-Y â you shouldn't need to worry about CountableRange
any more. That type was a workaround from before we had the ability to express that Range
was a Collection
when its Bound
was Strideable
. Now that Swift has conditional conformance, the CountableRange
type is just a typealias for Range
.
Thank you for pointing it out.
This message of the deprecated structure CountableClosedRange
should be "CountableClosedRange is now ClosedRange. ..."
.