// DictOfArraysToArrayOfDicts benchmark // // Description: Convert a dictionary of [key: [values]] to an array of // dictionaries [[key: value]] using zipWith. // Source: https://gist.github.com/airspeedswift/3675952127ee775551b0 import TestsUtils public let benchmarks = [ BenchmarkInfo( name: "DictOfArraysToArrayOfDicts", runFunction: run_DictOfArraysToArrayOfDicts, tags: [.algorithm, .Dictionary] ), ] @inline(never) public func run_DictOfArraysToArrayOfDicts(_ n: Int) { let returnedFromServer = [ "title": ["abc", "def", "ghi"], "time": ["1234", "5678", "0123"], "content": ["qwerty", "asdfg", "zxcvb"], ] var pairs: [[(String, String)]] = [] var inverted: [[(String, String)]] = [] var arrayOfDicts: [[String: String]] = [[:]] for _ in 1...100*n { pairs = returnedFromServer.map { (key, value) in value.map { (key, $0) } } inverted = zipWith(pairs[0], pairs[1], pairs[2]) { [$0] + [$1] + [$2] } arrayOfDicts = inverted .map { $0.map { (key: $0.0, value: $0.1) } } .map { Dictionary($0) } if !(arrayOfDicts.count == 3) { break } } check(arrayOfDicts.count == 3) } // Given [ // "title" : ["abc", "def"], // "time" : ["1234", "5678", "0123"], // "content":["qwerty", "asdfg", "zxcvb"] // ] // // how do you get to this: // // [ // ["title" : "abc", // "time" : "1234", // "content": "qwerty"], // ["title" : "def", // "time" : "5678", // "content": "asdfg"], // ["title" : "ghi", // "time" : "0123", // "content": "zxcvb"]] public func zip3 < A: Sequence,B: Sequence,C: Sequence > (_ a: A, _ b: B, _ c: C) -> ZipSequence3 { return ZipSequence3(a, b, c) } // Sequence of tuples created from values from three other sequences public struct ZipSequence3 { private var a: A private var b: B private var c: C public init (_ a: A, _ b: B, _ c: C) { self.a = a self.b = b self.c = c } } extension ZipSequence3 { public struct Iterator { private var a: A.Iterator private var b: B.Iterator private var c: C.Iterator public init(_ a: A, _ b: B, _ c: C) { self.a = a.makeIterator() self.b = b.makeIterator() self.c = c.makeIterator() } } } extension ZipSequence3.Iterator: IteratorProtocol { public typealias Element = (A.Element,B.Element,C.Element) public mutating func next() -> Element? { switch (a.next(), b.next(), c.next()) { case let (aValue?, bValue?, cValue?): return (aValue, bValue, cValue) default: return nil } } } extension ZipSequence3: Sequence { public typealias Element = (A.Element,B.Element,C.Element) public typealias SubSequence = AnySequence public func makeIterator() -> Iterator { return Iterator(a, b, c) } } // Iterator that creates tuples of values from three other generators func zipWith< A: Sequence, B: Sequence, C: Sequence, T >( _ a: A, _ b: B, _ c: C, _ combine: (A.Element,B.Element,C.Element) -> T ) -> [T] { return zip3(a,b,c).map(combine) } extension Dictionary { // Construct from an arbitrary sequence with elements of the tupe // `(Key,Value)` init (_ seq: S) where S.Iterator.Element == Element { self.init() self.merge(seq) } // Merge a sequence of `(Key,Value)` tuples into the dictionary mutating func merge (_ seq: S) where S.Element == Element { var gen = seq.makeIterator() while let (k, v) = gen.next() { self[k] = v } } }