I have this structure,
typealias Tweak = (
grab:(_ p: SomeClass)->CGFloat,
change:(_ p: SomeClass, _ n: CGFloat)->(),
from:CGFloat, upto:CGFloat
)
(So, the first line "gives you a value", the second "changes something", the last two are just limits.)
So, you might have an array of such things ...
var tweaks:[Tweak] = [
({_ in 0}, {_ in}, 0,0),
( {p in mainHeight},
{p, n in
mainHeight = n
paintDisplayWhatever()},
8.0, 28.0),
( {p in Some.global},
{p, n in
Some.global = n
fireball.adjust(heat: n)},
8.0, 28.0),
etc
My question ...
notice the first one in the array, I simply wanted it to be the "nothing" version of a Tweak
So, I did this
nothingTweak: Tweak = ({_ in 0}, {_ in}, 0,0)
In Swift is there a better way to do the two "nothing" closures, or indeed, a more correct way to do the whole thing?
nothingTweak: Tweak = lessNilThanNil
you know?
There's no built-in value that represents "a closure which returns a 0 CGFloat value", let alone a tuple of them along with two other zero values.
However if you create a type, such as a struct, to represent a Tweak (rather than using a typealias of a tuple), you can define static constant(s) to represent "default" values of a Tweak. For example:
class SomeClass {}
struct Tweak {
// feel free to rename me to something more appropriate
static let zero = Tweak(grab: {_ in 0 }, change: {_ in }, from: 0, upto: 0)
var grab: (_ p: SomeClass) -> CGFloat
var change: (_ p: SomeClass, _ n: CGFloat) -> Void
var from: CGFloat
var upto: CGFloat
}
Now wherever a Tweak is expected, you can just say .zero to refer to your "zero default" (this is exactly what types like CGPoint do):
var tweaks: [Tweak] = [
.zero,
Tweak(
grab: { p in 25 },
change: { p, n in
print(p, n)
},
from: 8, upto: 28
),
Tweak(
grab: { p in 27 },
change: { p, n in
print(p, n * 4)
},
from: 8, upto: 28
)
]
Creating a structure is much more preferable to creating a typealias of a tuple in this case. Tuples are only really designed to be transient types, not to be used for long-term storage. Structures are much more powerful and suited for long-term use.
Related
Imagine I want to create a function that, given an array of numbers, computes the square, cube, and fourth power of each number in an asynchronous fashion and returns a flattened, asynchronous sequence of all these results.
So, for example, for the input array [2, 3, 4], it should return an AsyncSequence instance yielding the elements [4, 8, 16, 9, 27, 81, 16, 64, 256].
Then let's say, instead of computing x^2, x^3, x^4, I would like it to compute x, x^2, x^3, ..., x^k where k is sort of a random integer that can be different for every x and is not known beforehand (its value comes to be known only as the powers are being computed). How would I implement such a pattern?
An AsyncStream could do the job. E.g., given an array of integers, values, the asynchronous sequence would be:
let stream = AsyncStream<Int> { continuation in
Task.detached {
for value in values {
var result = value
for _ in 1 ..< n {
result *= value
continuation.yield(result)
}
}
continuation.finish()
}
}
But this calculation of x², x³, ..., xⁿ for each element in the input array might not be a good candidate for an asynchronous sequence. Each subsequent value can be calculated nearly instantaneously (just multiplying the previously emitted value by x) and, as such, should probably just be a standard, synchronous sequence.
Generally, asynchronous sequences should be those that are sufficiently slow to justify moving it into the background or otherwise has results that are emitted asynchronously over time.
Thanks a lot to Rob for providing the basic idea on how to implement something like this.
I wrote it in the following way:
func powers(of numbers: [Int]) -> AsyncStream<Int> {
return AsyncStream<Int> { continuation in
Task {
for number in numbers {
for await power in Powers(of: number) {
continuation.yield(power)
}
}
continuation.finish()
}
}
}
struct Powers: AsyncSequence {
init(of base: Int) {
self.base = base
}
func makeAsyncIterator() -> PowersIterator {
return PowersIterator(base: self.base)
}
let base: Int
typealias Element = Int
}
struct PowersIterator: AsyncIteratorProtocol {
mutating func next() async -> Int? {
if !self.shouldFinish() {
try? await Task.sleep(nanoseconds: 1_000_000_000)
defer {
self.exponent += 1
}
return power(self.base, self.exponent)
} else {
return nil
}
}
private func shouldFinish() -> Bool {
return Int.random(in: 1...10) == 1
}
private func power(_ base: Int, _ exponent: UInt) -> Int {
return (0..<exponent).reduce(1) { power, _ in power * base }
}
var exponent = UInt(1)
let base: Int
}
It can be invoked using this code:
Task {
let numbers = [1, 2, 3, 4, 5]
for await power in powers(of: numbers) {
print(power, terminator: " ")
}
}
Possible output:
1 1 1 2 4 8 16 32 64 3 9 27 4 16 64 256 5 25 125 625 3125 15625
The solution is a little more complex than it ought to be. But that's of course because I actually wanted to compute something that would really need to be computed asynchronously and has the same computational structure as this example. That is also the reason for why I created a separate async sequence for computing the powers.
If this helps anyone out, I'll be glad.
I have a function in swift, as below. There is a loop with a reference to variables existing within an instance of this class. (fftfilterbankReal is an array in the class). However after one pass, I get an error with 'index out of range' at the code line 'for i in 0..
In the debugger it seems that on the 2nd iteration of this loop, there are no variables under the 'self' drop down.
If I comment out the line 'vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)' then the loop runs and I can debug at any time and visually see the self variables in the debugger.
What am I missing that seems to make these variables disappear? I have read into memory allocation and such, and my class variables are declared using 'var' and nothing more, as that should default to strong in swift.
func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
realResult = Array(repeating: [], count: filterbankReal.count)
imagResult = Array(repeating: [], count: filterbankReal.count)
let x = realsamples
let y = imagsamples
var N = x.count
var logN = 16
var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var paddedLength = x.count + filterbankReal.count - 1
var halfPaddedLength = paddedLength/2
var halfKernelLength = kernelLength/2
//setup Complex Buffer 1
var reals = [Float]()
var imags = [Float]()
for i in 0..<x.count{
reals.append(x[i])
imags.append(y[i])
}
var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))
//Perform FFT on incoming samples
var re = [Float](repeating:0.0, count: N)
var im = [Float](repeating:0.0, count: N)
var fft1Input = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: re), imagp: UnsafeMutablePointer(mutating: im))
var fftlength = 10
vDSP_fft_zop(fft1Setup, &(complexBuffer1), 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))
//Remove DC from FFT Signal
re.remove(at: 0)
im.remove(at: 0)
for i in 0..<self.fftfilterbankReal.count {
var r:[Float] = self.fftfilterbankReal[i]
var im:[Float] = self.fftfilterbankImag[i]
var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)
var res:Float = 0
var ims:Float = 0
var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)
self.realResult[i].append(res)
self.imagResult[i].append(ims)
}
Your code is sort of a showcase of bad usages when working with Arrays and pointers.
For example:
var complexBuffer1 = DSPSplitComplex(realp: UnsafeMutablePointer(mutating: reals), imagp: UnsafeMutablePointer(mutating: imags))
or:
var kernel:DSPSplitComplex? = DSPSplitComplex(realp: &r, imagp: &im)
DSPSplitComplex holds two pointers for real part and imaginary part separately and does not copy the contents. You should not pass Swift Arrays for such parameters.
And the most critical part in your code is...
var res:Float = 0
var ims:Float = 0
var result:DSPSplitComplex = DSPSplitComplex(realp: &res, imagp: &ims)
vDSP_zvmul(&kernel!, 1, &fft1Input, 1, &result, 1, vDSP_Length(r.count), 1)
vDSP_zvmul generates N (in your code N = vDSP_Length(r.count)) complex numbers, so you need to prepare a region which can hold N elements.
Once you call vDSP_zvmul with your current code, you break whole stack contents which causes what you have experienced:
In the debugger it seems that on the 2nd iteration of this loop, there
are no variables under the 'self' drop down.
You are hiding many parts of your code, so it is very hard to guess what you really want to do, but if I re-write your code in safer manner, it would be something like this:
func convolveInput(realsamples:[Float], imagsamples:[Float]) -> [Float]{
realResult = Array(repeating: [], count: filterbankReal.count)
imagResult = Array(repeating: [], count: filterbankReal.count)
let x = realsamples
let y = imagsamples
var N = x.count
var logN = 16
var fft1Setup = vDSP_create_fftsetup(UInt(logN), FFTRadix(FFT_RADIX2))!
var paddedLength = x.count + filterbankReal.count - 1
var halfPaddedLength = paddedLength/2
var halfKernelLength = kernelLength/2
//setup Complex Buffer 1
var reals = UnsafeMutableBufferPointer<Float>.allocate(capacity: x.count)
defer {reals.deallocate()}
var imags = UnsafeMutableBufferPointer<Float>.allocate(capacity: y.count)
defer {imags.deallocate()}
_ = reals.initialize(from: x)
_ = imags.initialize(from: y)
var complexBuffer1 = DSPSplitComplex(realp: reals.baseAddress!, imagp: imags.baseAddress!)
//Perform FFT on incoming samples
var re = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
defer {re.deallocate()}
var im = UnsafeMutableBufferPointer<Float>.allocate(capacity: N)
defer {im.deallocate()}
var fft1Input = DSPSplitComplex(realp: re.baseAddress!, imagp: im.baseAddress!)
let fftlength = 10
vDSP_fft_zop(fft1Setup, &complexBuffer1, 1, &fft1Input, 1, UInt(fftlength), Int32(FFT_FORWARD))
//Remove DC from FFT Signal
fft1Input = DSPSplitComplex(realp: re.baseAddress!+1, imagp: im.baseAddress!+1)
for i in 0..<self.fftfilterbankReal.count {
self.fftfilterbankReal[i].withUnsafeMutableBufferPointer {rBuf in
self.fftfilterbankImag[i].withUnsafeMutableBufferPointer {imBuf in
var kernel = DSPSplitComplex(realp: rBuf.baseAddress!, imagp: imBuf.baseAddress!)
var res = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
defer {res.deallocate()}
var ims = UnsafeMutableBufferPointer<Float>.allocate(capacity: rBuf.count)
defer {ims.deallocate()}
var result:DSPSplitComplex = DSPSplitComplex(realp: res.baseAddress!, imagp: ims.baseAddress!)
vDSP_zvmul(&kernel, 1, &fft1Input, 1, &result, 1, vDSP_Length(rBuf.count), 1)
//vDSP_zvmul generates `N` complex numbers,
// I do not understand what you really want to do...
self.realResult[i].append(res[0])
self.imagResult[i].append(ims[0])
}
}
}
//...
}
There may be other parts to fix, but anyway, please try and see what you get.
Foreword: Boy, sifting through all this took me almost 2 hours, and it's still not even perfect, but boy is this much nicer. I hope it helps!
Your code is suffer massively because the Accelerate APIs are C APIs that are not adapted to take advantage of Swift features. You will have much more readable code if you make yourself some nice wrappers for the Accelerate API, which lets you tuck all the "Ugly stuff" away into a corner you seldom have to see or edit.
I did this by creating a new type, ComplexFloatArray, which is similar to DSPSplitComplex, but actually encapsulates and owns its buffers. This prevents the dangling buffers that DSPSplitComplex is susceptible to.
After dining the ComplexFloatArray types, it's time to define some wrappers for the the Accelerate functions you used. In this case, vDSP_zvmul and vDSP_fft_zop. Since C doesn't have tuples, returning multiple values from a C function usually requires that you use out-parameters, which are used pervasively in the Accelerate framework. We can re-design these as Swift functions with regular return types. These APIs are very naturally expressed as instance methods that operate on ComplexFloatArray, so we'll put them there.
Additionally, your code is made much more complex by its dependance on external state. Convolution is a function, there's no reason why it does anything besides taking in input (via parameters, and not via instance variables) and returns the result (via return value, and not via instance variables).
import Accelerate
class ComplexFloatArray {
var reals: [Float]
var imaginaries: [Float]
init(reals: [Float], imaginaries: [Float]) {
self.reals = reals
self.imaginaries = imaginaries
}
}
extension ComplexFloatArray { // Core features
var count: Int {
assert(reals.count == imaginaries.count)
return reals.count
}
static let stride = 1
func append(real: Float, imaginary: Float) {
self.reals.append(real)
self.imaginaries.append(imaginary)
}
func useAsDSPSplitComplex<R>(_ closure: (inout DSPSplitComplex) -> R) -> R {
return reals.withUnsafeMutableBufferPointer { realBufferPointer in
return imaginaries.withUnsafeMutableBufferPointer { imaginaryBufferPointer in
var dspSplitComplex = DSPSplitComplex(realp: realBufferPointer.baseAddress!, imagp: imaginaryBufferPointer.baseAddress!)
return closure(&dspSplitComplex)
}
}
}
}
extension ComplexFloatArray { // Convenience utilities
convenience init() {
self.init(reals: [], imaginaries: [])
}
static func zeros(count: Int) -> ComplexFloatArray {
return ComplexFloatArray(reals: Array(repeating: 0, count: count), imaginaries:Array(repeating: 0, count: count))
}
}
extension ComplexFloatArray { // Vector multiplciation extensions
enum ComplexMultiplicationType: Int32 { case normal = 1, conjugate = -1 }
func complexMultiply(
with other: ComplexFloatArray,
multiplicationType: ComplexMultiplicationType = .normal
) -> ComplexFloatArray {
assert(self.count == other.count, "Multiplied vectors must have the same size!")
let result = ComplexFloatArray.zeros(count: self.count)
self.useAsDSPSplitComplex { selfPointer in
other.useAsDSPSplitComplex { otherPointer in
result.useAsDSPSplitComplex { resultPointer in
vDSP_zvmul(
&selfPointer, ComplexFloatArray.stride,
&otherPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride, vDSP_Length(result.count),
multiplicationType.rawValue)
}
}
}
return result
}
}
extension ComplexFloatArray { // FFT extensions
enum FourierTransformDirection: Int32 { case forward = 1, inverse = -1 }
//TODO: name log2n label better
func outOfPlaceComplexFourierTransform(
setup: FFTSetup,
resultSize: Int,
log2n: UInt,
direction: FourierTransformDirection
) -> ComplexFloatArray {
let result = ComplexFloatArray.zeros(count: resultSize)
self.useAsDSPSplitComplex { selfPointer in
result.useAsDSPSplitComplex{ resultPointer in
vDSP_fft_zop(
setup,
&selfPointer, ComplexFloatArray.stride,
&resultPointer, ComplexFloatArray.stride,
log2n,
direction.rawValue
)
}
}
return result
}
}
extension FFTSetup {
enum FourierTransformRadix: Int32 {
case radix2 = 0, radix3 = 1, radix5 = 2
// Static let constants are only initialized once
// This function's intent to to make sure this enum stays in sync with the raw constants the Accelerate framework uses
static let assertRawValuesAreCorrect: Void = {
func assertRawValue(for actual: FourierTransformRadix, isEqualTo expected: Int) {
assert(actual.rawValue == expected, "\(actual) has a rawValue of \(actual.rawValue), but expected \(expected).")
}
assertRawValue(for: .radix2, isEqualTo: kFFTRadix2)
assertRawValue(for: .radix3, isEqualTo: kFFTRadix3)
assertRawValue(for: .radix5, isEqualTo: kFFTRadix5)
}()
}
init(log2n: Int, _ radix: FourierTransformRadix) {
_ = FourierTransformRadix.assertRawValuesAreCorrect
guard let setup = vDSP_create_fftsetup(vDSP_Length(log2n), FFTRadix(radix.rawValue)) else {
fatalError("vDSP_create_fftsetup(\(log2n), \(radix)) returned nil")
}
self = setup
}
}
struct NameMe {
// I don't know what this is, but if it can somehow be removed,
// the whole convolveInput method could be moved into an extension on ComplexFloatArray.
var fftFilterBank: [ComplexFloatArray]
func convolve(samples: ComplexFloatArray) -> [ComplexFloatArray] {
// TODO: rework reimplement this code to remove the DC from samples, and add it back in
// //Remove DC from FFT Signal
// re.remove(at: 0)
// im.remove(at: 0)
let fftlength: UInt = 10 // Todo: what is this, exactly?
let fft1Input = samples.outOfPlaceComplexFourierTransform( // Rename me to something better
setup: FFTSetup(log2n: 16, .radix2),
resultSize: samples.count,
log2n: fftlength,
direction: .forward
)
return self.fftFilterBank.map { kernel in kernel.complexMultiply(with: fft1Input) }
}
// Stub for compatibility with the old API. Deprecate it and move to the
// `convolve(samples: ComplexFloatArray) -> [ComplexFloatArray]` as soon as possible.
func convolveInput(realsamples: [Float], imagsamples: [Float]) -> [ComplexFloatArray] {
return self.convolve(samples: ComplexFloatArray(reals: realsamples, imaginaries: imagsamples))
}
}
I have some notes along the way
This function is WAAAAAAAAAAAY too long. If you have a function that's over 10 lines long, there's a fairly strong indicator that it's growing too large, does to many things, and could benefit from being broken down into simpler steps.
You have lots of redundant variables. You don't need more than 1 copy of any given immutable value. You have all these different names, referring to the same thing, which just complicates things. There might be an argument to be made that this can be useful if the new names have significance, but names like x, y, re, im are near-useless in their communicative ability, and should almost-always be avoided entirely.
Arrays are value types with Copy-on-Write. You can make copies of them by simply assigning to them to a new variable, so code like:
var reals = [Float]()
var imags = [Float]()
for i in 0..<x.count{
reals.append(x[i])
imags.append(y[i])
}
Is both slow, and visually cumbersome. This could be simply: let (reals, imags) = (x, y). But again, these copies are unnecessary (as are x and y). Remove them, and just use realsamples and imagsamples directly.
When you find yourself frequently passing multiple pieces of data together, that's a very strong indication that you should define a new aggregate type to wrap them. For example, if you're passing two Array<Float> to represent complex vectors, you should define a ComplexVector type. This can let you enforce invariants (e.g. there are always as many real values as imaginary values), and add convenient operations (e.g. a func append(real: Float, imaginary: Float), which operates on both simultaneously, ensuring you can never forget to append to one of the arrays).
In closing,
There's a lot going on here, so I can't possible pre-empt every question and explain it ahead of time. I encourage you to take some time, read through this, and feel free to ask me any follow up questions.
I suspect I've made mistakes during my refactor (because I had no test cases to work with), but the code is modular enough that it should be very simple to isolate and fix and bugs.
I am new in Swift.
I have an error with this code and I can't find any answer on this site.
I print largest number but I want to print largest number's kind.
let interestingNumbers = [
"Prime": [2,3,5,7,11,13],
"Fibonacci": [1,1,2,3,5,8,13],
"Square": [1,4,9,16,25,36]
]
var largestNumber = 0
for (kind, numbers) in interestingNumbers {
for x in numbers {
for y in kind {
if x > largestNumber {
largestNumber = x
}
}
}
}
print("the largest number is = \(largestNumber)")
Try this instead:
var largestNumber = 0
var largestNumberKind: String!
for (kind, numbers) in interestingNumbers {
for x in numbers {
if x > largestNumber {
largestNumber = x
largertNumberKind = kind
}
}
}
print("the largest number is = \(largestNumber)")
print("the largest number kind is = \(largestNumberKind)")
Regarding your original code:
you were only keeping track of the largest number, losing the kind info you wanted. The largestNumberKind variable I added does just that.
looping over the kind: String didn't make any sense (the for y in kind line). Your outside loop already iterates a key at a time, so such inner loop is pointless.
There is nothing wrong with Paulo's approach (with some minor corrections; see comments there), but this is a reasonable problem to explore more functional approaches that don't require looping and mutation.
For example, we can just flatten each kind to its maximum element (or Int.min if it's empty), then take the kind with the highest max:
interestingNumbers
.map { (kind: $0, maxValue: $1.max() ?? .min) } // Map each kind to its max value
.max { $0.maxValue < $1.maxValue }? // Find the kind with the max value
.kind // Return the kind
This does create a slight edge condition that I don't love. If you evaluate the following:
let interestingNumbers = [
"ImaginaryReals": [],
"Smallest": [Int.min],
]
It's not well defined here which will be returned. Clearly the correct answer is "Smallest," but it's kind of order-dependent. With a little more thought (and code) we can fix this. The problem is that we are taking a little shortcut by treating an empty list as having an Int.min maximum (this also prevents our system from working for things like Float, so that's sad). So let's fix that. Let's be precise. The max of an empty list is nil. We want to drop those elements.
We can use a modified version of mapValues (which is coming in Swift 4 I believe). We'll make flatMapValues:
extension Dictionary {
func flatMapValues<T>(_ transform: (Value) throws -> T?) rethrows -> [Key: T] {
var result: [Key: T] = [:]
for (key, value) in self {
if let newValue = try transform(value) {
result[key] = newValue
}
}
return result
}
}
And with that, we can be totally precise, even with empty lists in the mix:
interestingNumbers
.flatMapValues { $0.max() }
.max { $0.1 < $1.1 }?
.key
Again, nothing wrong with Paulo's approach if you find it clear, but there are other ways of thinking about the problem.
BTW, the equivalent version that iterates would look like this:
var largestNumber: Int? = nil
var largestNumberKind: String? = nil
for (kind, numbers) in interestingNumbers {
for x in numbers {
if largestNumber == nil || largestNumber! < x {
largestNumber = x
largestNumberKind = kind
}
}
}
Is there an elegant way to make a custom operator that updates a dictionary value?
More specifically, I want a prefix operator that increments the integer value corresponding to a given key:
prefix operator +> {}
prefix func +> //Signature
{
...
}
var d = ["first" : 10 , "second" : 33]
+>d["second"] // should update d to ["first" : 10 , "second" : 34]
This is feasible using the functional way. For example, to calculate the frequencies of elements in an array:
func update<K,V>(var dictionary: [K:V], key: K, value: V) -> [K:V] {
dictionary[key] = value
return dictionary
}
func increment<T>(dictionary: [T:Int], key: T) -> [T:Int] {
return update(dictionary, key: key, value: dictionary[key].map{$0 + 1} ?? 1)
}
func histogram<T>( s: [T]) -> [T:Int] {
return s.reduce([T:Int](), combine: increment)
}
let foo = histogram([1,4,3,1,4,1,1,2,3]) // [2: 1, 3: 2, 1: 4, 4: 2]
But I am trying to do the same thing using a custom operator
var d = ["first" : 10 , "second" : 33]
d["second"]?++
The operator could be implemented like this:
prefix operator +> {}
prefix func +> <I : ForwardIndexType>(inout i: I?) {
i?._successorInPlace()
}
var dict = ["a":1, "b":2]
+>dict["b"]
dict // ["b": 3, "a": 1]
Although I'm not sure how it would give you a frequencies function - I mean, if it's building a dictionary, it's not going to have any keys to begin with, so there won't be anything to increment. There are a bunch of cool ways to do it, though. Using the postfix ++, you can do this:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self {
result[element]?++ ?? {result.updateValue(1, forKey: element)}()
}
return result
}
}
Airspeed Velocity tweeted another cool way:
extension Dictionary {
subscript(key: Key, or or: Value) -> Value {
get { return self[key] ?? or }
set { self[key] = newValue }
}
}
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for element in self { ++result[element, or: 0] }
return result
}
}
Or, using an undocumented function:
extension SequenceType where Generator.Element : Hashable {
func frequencies() -> [Generator.Element:Int] {
var result: [Generator.Element:Int] = [:]
for el in self {result[el]?._successorInPlace() ?? {result[el] = 1}()}
return result
}
}
First, look for a way to do it using functions (not custom operators). You want a function that takes a reference to an item (from a dictionary) and updates its value... that calls for an inout parameter type.
func increment(inout n: Int) {
n++
}
var d = ["first" : 10 , "second" : 33]
increment(&d["first"]!)
print(d) // -> "[first: 11, second: 33]"
You don't have to care about the value being in a dictionary — inout takes any kind of reference and updates it directly. (This even goes for computed properties. You can pass one inout and it'll correctly go through the setter and getter as it reads and writes values.) And because you don't have to care about the dictionary, you don't really need to be generic — if you want a function that works on dictionaries with Ints, just make a function that works on Ints and let inout do the rest.
Now, custom operators are just functions, so make an operator of your function:
prefix operator +> {}
prefix func +>(inout n: Int) {
n++
}
You can't use exactly the syntax you were asking for to invoke it, though: dictionary lookups always result in Optional types, so you have to unwrap.
+>d["second"] // error
+>d["second"]! // but this works — operators automatically make params inout as needed
print(d) // -> "[first: 11, second: 34]"
This is a little uglier than you probably are looking for, but you can accomplish it using an unsafe mutable pointer in a generic overloaded operator:
prefix operator +> {}
prefix func +><T>( value:UnsafeMutablePointer<T?> )
{
print( value.memory )
if let intValue = value.memory as? Int {
value.memory = (intValue + 1) as? T
}
}
var d = ["first" : 10 , "second" : 33]
print( d["second"] ) // Optional(33)
+>(&d["second"])
print( d["second"] ) // Optional(34)
struct MapVector {
var distance: Double
var bearing: Double
}
func distanceAndBearing() -> [MapVector] {
var points = self.mapPoints
var currPoint:CLLocation = points.first!
points.removeAtIndex(0)
var result: [MapVector] = []
for point: CLLocation in points {
let calc = PointCalculator(initialPoint: currPoint, nextPoint: point)
let v = MapVector(distance: calc.pointDistance, bearing: calc.bearing)
result.append(v)
currPoint = point
}
return result
}
I am working in Swift on an application using map coordinates. I have a an array of CLLocations from which I would like to create an array of distances and bearings. The above code (its slightly simplified for readability, so may not be 100% correct) achieves that but I'd like to do it in a neater way. Is this something that can be done with map or filter? Still trying to get my head around the FP way of doing things.
Here is a simplified example for the same problem except the calculations:
let numbers = [3, 7, 2, 8, 3, 7, 5]
let result = numbers.isEmpty ? [] :
map(zip(numbers, numbers[1..<numbers.count])) {
(x, y) in
return (diff: x - y, mult: x * y)
}
result[0].diff // -4
result[0].mult // 21
Here I compute the differences and the multiplications of the numbers.
Note this will work only for Swift 1.2
In case you need it for earlier version, you should explore the use of Zip2.
For reference here are alternative solutions I came up with:-
func distanceAndBearing2() -> [MapVector]
{
// make the removeAtIndex(0) part safe
if (self.mapPoints.count == 0) {
return []
}
var t2 = self.mapPoints
t2.removeAtIndex(0)
let t3 = zip(self.mapPoints, t2)
return Array(t3).map({
(p1, p2) in
return PointCalculator(initialPoint: p1, nextPoint: p2).toMapVector()
})
}
This uses the new zip method from Xcode 6.3 Beta 2, and I moved the conversion to MapVector into the PointCalculator struct
func distanceAndBearing3() -> [MapVector] {
// make the shift part safe
if (self.mapPoints.count == 0) {
return []
}
var points = self.mapPoints
var currPoint = points.shift()!
return points.map {
point in
let initialPoint = currPoint
currPoint = point
return LocationPair(initialPoint: initialPoint,
nextPoint: point).toMapVector()
}
}
And this version uses the same toMapVector method on the PointCalculator struct, but uses a variable outside the map function which is updated by the map function; this feels like its not "correct"