Swift array loop once, write many -
consider following silly, simple example:
let arr = ["hey", "ho"] let doubled = arr.map {$0 + $0} let capitalized = arr.map {$0.capitalizedstring}
as can see, i'm processing same initial array in multiple ways in order end multiple processed arrays.
now imagine arr
long , have many such processes generating many final arrays. don't above code because looping multiple times, once each map
call. i'd prefer loop once.
now, handle brute force, i.e. starting multiple mutable arrays , writing of them on each iteration:
let arr = ["hey", "ho"] var doubled = [string]() var capitalized = [string]() s in arr { doubled.append(s + s) capitalized.append(s.capitalizedstring) }
fine. don't joy of using map
. question is: there better, swiftier way? in hazy way imagine myself using map
, or map
, generate tuple , magically splitting tuple out resulting arrays iterate, if (pseudocode, don't try @ home):
let arr = ["hey", "ho"] let (doubled, capitalized) = arr.map { /* ???? */ }
if designing own language, might permit kind of splatting assignment pseudo-array of lvalues:
let arr = ["hey", "ho"] let [doubled, capitalized] = arr.map { /* ???? */ }
no big deal if can't done, fun able talk way.
how function, multimap
, takes collection of transformations, , applies each one, returning them array of arrays:
// yay protocol extensions extension sequencetype { // looks t->u works ok constraint func multimap <u, c: collectiontype c.generator.element == generator.element->u> (transformations: c) -> [[u]] { return transformations.map { self.map($0) } } }
then use this:
let arr = ["hey", "ho"] let double: string->string = { $0 + $0 } let uppercase: string->string = { $0.uppercasestring } arr.multimap([double, uppercase]) // returns [["heyhey", "hoho"], ["hey", "ho"]]
or might quite nice in variadic form:
extension sequencetype { func multimap<u>(transformations: (generator.element->u)...) -> [[u]] { return self.multimap(transformations) } } arr.multimap({ $0 + $0 }, { $0.uppercasestring })
edit: if want separate variables, think best can destructure
function (which have declare n times each n-tuple unfortunately):
// don't think can't expressed protocol extension quite yet func destructure<c: collectiontype>(source: c) -> (c.generator.element,c.generator.element) { precondition(source.count == 2) return (source[source.startindex],source[source.startindex.successor()]) } // and, since it's function, let's declare pipe forward // make easier call infix operator |> { } func |> <t,u>(lhs: t, rhs: t->u) -> u { return rhs(lhs) }
and can declare variables this:
let (doubled,uppercased) = arr.multimap({ $0 + $0 }, { $0.uppercasestring }) |> destructure
yes teensy bit inefficient because have build array rip apart – that’s not going material, since arrays copy-on-write , we’re talking small number of them in outer array.
edit: excuse use new guard
statement:
func destructure<c: sliceable c.subslice.generator.element == c.generator.element>(source: c) -> (c.generator.element,c.generator.element) { guard let 1 = source.first else { fatalerror("empty source") } guard let 2 = dropfirst(source).first else { fatalerror("insufficient elements") } return (one,two) }
Comments
Post a Comment