Reputation: 2031
x
is an object that holds an array called point.
x
implements the subscript operator so you can do things, like x[i]
to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T>
is not convertible to Int/Double.
Edit1:
Here is my object x
:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x
as [1.0,2.0,0.0]
I can get the first n
elements via x[0...2]
.
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]
. This does not work as can be seen in the answers. I want to update x
without iteration (on my end) and by hiding the fact that x
is not an array (even though it is not).
Upvotes: 4
Views: 2331
Reputation: 40965
[0...2]
is an array with one element which, at best, will be a Range<Int>
from 0 through 2. You can't assign that to a slice containing, say, Int
s.
x[0...2]
on the other hand is (probably) a slice, and Sliceable
only defines a get
subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2
, which at least is attempting to replace a range within x
with the values of a similarly-sized collection - it still wouldn't work.
edit: as @rintaro points out, Array does support a setter subscript for ranges – so if x
were a range you could do x[0...2] = Slice(0...2)
– but it has to be a slice you assign, so I'd still go with replaceRange
.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange
, as long as your collection conforms to RangeReplaceableCollection
(which, for example, Array
does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y
don't have to be the same size, the collection will expand/contract as necessary.
Also, y
doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point
class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
Upvotes: 6
Reputation: 299345
You need to implement subscript(InvervalType)
to handle the case of multiple assignments like this. That isn't done for you automatically.
Upvotes: 0