Today, I was kicking around in a playground because (1) writing about playgrounds is kind of a thing right now and (2) because my kids were away and I had some time. I started trying to mess with tuples, and more specifically to zip them because tuples and structs tend to have related data in similar positions.
In any case, I ended up creating a small set of what I call EVIL UNIVERSE SPOCK UTILITIES using mirroring and goatees. I thought I’d throw these out there to see whether they’re generally useful or interesting:
// MARK: Mirror-based Utilities // These work across arrays, structures, tuples // Goatees are mandatory // This function maps a closure across anything func mirrorDo<S>(structure:S, closure:(Int, String, Any)->()) { let mirror = reflect(structure) for index in 0 ..< mirror.count { closure(index, mirror[index].0, mirror[index].1.value) } } // This function collects the results of the mapped closure func mirrorMap<S>(structure:S, closure:(Int, String, Any)->Any)->[Any]{ let mirror = reflect(structure) var results = [Any]() for index in 0 ..< mirror.count { let result = closure(index, mirror[index].0, mirror[index].1.value) results += [result] } return results } // This converts nearly anything into an array func mirrorToArray<S>(structure:S) -> [Any] { return mirrorMap(structure){return $2} } // This function zips things into array pairs func mirrorZipToArray<S, T>(s:S, t:T)->[[Any]] { var array = [[Any]]() for each in zip(mirrorToArray(s), mirrorToArray(t)) { array += [mirrorToArray(each)] } return array }
For example, you might look at all the elements or fields in a tuple or structure:
for test : Any in [tuple1, rect, point, transform] { println("\(test.dynamicType): ") mirrorDo(test){ (index: Int, field : String, value : Any) -> () in println("type:\(value.dynamicType), index: \(index), field: \(field), value: \(value)") } }
Or you might convert items to an array:
for test : Any in [tuple1, rect, array2, point, transform] { println("Converting \(test) to array") println(mirrorToArray(test)) }
Or you might just zip stuff together into arrays:
mirrorZipToArray(array3, array2) mirrorZipToArray(tuple1, tuple2)
You’ll find the code and a bunch of examples that showcase their use in this gist.
Two other things that simply pleased my aesthetics today. First: I really like that you can apply maps to zips.
var results = map(zip(["a", "b", "c"], ["d", "b", "e"])){$0==$1}
And also you can pass tuples to functions and closures as parameter sets:
func plus(a: Int, b: Int) -> Int {return a + b} let xx = (2, 3); let yy = (5, 9) plus(xx) plus(yy)
Best of all, you can combine these approaches to zip and then use the tuples in a function call like this:
map(zip([1, 2, 3, 4], [5, 6, 7, 8])){plus($0)}
Isn’t that cool for a boring Sunday?
Comments are closed.