Skip to content

Instantly share code, notes, and snippets.

@airspeedswift
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save airspeedswift/3675952127ee775551b0 to your computer and use it in GitHub Desktop.
Save airspeedswift/3675952127ee775551b0 to your computer and use it in GitHub Desktop.
Converting a dictionary of [key : [values]] to a an array of dictionaries [ [key:value] ] using zipWith
// from http://stackoverflow.com/questions/27635981/transform-from-dictionary-to-array-in-swift-without-a-for-loop
//
// 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"]]
// --- Begin helpers: zip3, zipWith and Dictionary init from pairs
// This version of zip3 taken from Kris Johnson's version here: https://gist.github.com/kristopherjohnson/04dbc470e17f67f836a2
public func zip3<A: SequenceType, B: SequenceType, C: SequenceType>(a: A, b: B, c: C)
-> ZipSequence3<A, B, C>
{
return ZipSequence3(a, b, c)
}
// Sequence of tuples created from values from three other sequences
public struct ZipSequence3<A: SequenceType, B: SequenceType, C: SequenceType>: SequenceType {
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
}
public func generate() -> ZipGenerator3<A.Generator, B.Generator, C.Generator> {
return ZipGenerator3(a.generate(), b.generate(), c.generate())
}
}
// Generator that creates tuples of values from three other generators
public struct ZipGenerator3<A: GeneratorType, B: GeneratorType, C: GeneratorType>: GeneratorType {
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
}
mutating public func next() -> (A.Element, B.Element, C.Element)? {
switch (a.next(), b.next(), c.next()) {
case let (.Some(aValue), .Some(bValue), .Some(cValue)):
return (aValue, bValue, cValue)
default:
return nil
}
}
}
func zipWith
<S1: SequenceType, S2: SequenceType, S3: SequenceType, T>
(s1: S1, s2: S2, s3: S3, combine: (S1.Generator.Element,S2.Generator.Element,S3.Generator.Element) -> T)
-> [T] {
return map(zip3(s1,s2,s3),combine)
}
extension Dictionary {
/// Construct from an arbitrary sequence with elements of the tupe `(Key,Value)`
init<S: SequenceType
where S.Generator.Element == Element>
(_ seq: S) {
self.init()
self.merge(seq)
}
/// Merge a sequence of `(Key,Value)` tuples into the dictionary
mutating func merge<S: SequenceType
where S.Generator.Element == Element>
(seq: S) {
var gen = seq.generate()
while let (k: Key, v: Value) = gen.next() {
self[k] = v
}
}
}
--- end helpers
let returnedFromServer = [
"title" : ["abc", "def"],
"time" : ["1234", "5678", "0123"],
"content":["qwerty", "asdfg", "zxcvb"]
]
let pairs = map(returnedFromServer) { (key,value) in map(value) { (key, $0) } }
// todo: a version of zipWith that takes a sequence of sequences
// (would have the downside of needing key and value in this case to be same type)
let inverted = zipWith(pairs[0],pairs[1],pairs[2]) { [$0] + [$1] + [$2] }
let arrayOfDicts = inverted.map { Dictionary($0) }
println(arrayOfDicts)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment