我从服务器返回的一些数据如下所示:
let returnedFromServer = ["title" : ["abc", "def", "ghi"],
"time" : ["1234", "5678", "0123"],
"content":["qwerty", "asdfg", "zxcvb"]]
我想把它变成这样的东西:
let afterTransformation =
[["title" : "abc",
"time" : "1234",
"content": "qwerty"],
["title" : "def",
"time" : "5678",
"content": "asdfg"],
["title" : "ghi",
"time" : "0123",
"content": "zxcvb"]]
我目前的实施如下:
var outputArray = [[String : AnyObject]]()
for i in 0..<(returnedFromServer["time"] as [String]).count {
var singleDict = [String: AnyObject]()
for attribute in returnedFromServer {
singleDict[attribute] = returnedFromServer[attribute]?[i]
}
outputArray.append(singleDict)
}
这很好但我认为这不是一个非常优雅的解决方案。鉴于Swift有一些简洁的功能,如 reduce ,过滤器和 map ,我想知道如果不明确使用循环我是否能做同样的工作。
感谢您的帮助!
答案 0 :(得分:4)
使用想法和字典扩展
extension Dictionary {
init(_ pairs: [Element]) {
self.init()
for (k, v) in pairs {
self[k] = v
}
}
func map<OutKey: Hashable, OutValue>(transform: Element -> (OutKey, OutValue)) -> [OutKey: OutValue] {
return Dictionary<OutKey, OutValue>(Swift.map(self, transform))
}
}
这
您可以通过
实现这一目标let count = returnedFromServer["time"]!.count
let outputArray = (0 ..< count).map {
idx -> [String: AnyObject] in
return returnedFromServer.map {
(key, value) in
return (key, value[idx])
}
}
答案 1 :(得分:2)
Martin R的答案很好,您应该使用它并接受他的答案:-),但作为思考的替代方案:
在理想的世界中,Swift标准库将具有:
如果你拥有所有这些,你可以写下以下内容:
let pairs = map(returnedFromServer) { (key,value) in map(value) { (key, $0) } }
assert(pairs.count == 3)
let inverted = zipWith(pairs[0],pairs[1],pairs[2]) { [$0] + [$1] + [$2] }
let arrayOfDicts = inverted.map { Dictionary($0) }
这样做的好处是对粗糙的输入具有鲁棒性 - 它只会在输入中生成最短列表中的那些元素(不同于从输入的一个特定列表中获取计数的解决方案)。它的缺点是硬编码为3,但可以通过一个更通用的zipWith版本来修复,它采用了一系列序列(尽管你真的希望你的键是字符串,值是AnyObject
不是你必须得到更好的字符串。
这些功能并不是你自己写的那么难 - 尽管为这种一次性的情况写作显然需要付出太多努力,但它们在多种情况下都很有用。如果您有兴趣,我会在this gist中完整实施。
答案 2 :(得分:1)
我会创建2个助手:
ZipArray(类似于Zip2
,但可以使用任意长度):
struct ZipArray<S:SequenceType>:SequenceType {
let _sequences:[S]
init<SS:SequenceType where SS.Generator.Element == S>(_ base:SS) {
_sequences = Array(base)
}
func generate() -> ZipArrayGenerator<S.Generator> {
return ZipArrayGenerator(map(_sequences, { $0.generate()}))
}
}
struct ZipArrayGenerator<G:GeneratorType>:GeneratorType {
var generators:[G]
init(_ base:[G]) {
generators = base
}
mutating func next() -> [G.Element]? {
var row:[G.Element] = []
row.reserveCapacity(generators.count)
for i in 0 ..< generators.count {
if let e = generators[i].next() {
row.append(e)
}
else {
return nil
}
}
return row
}
}
基本上,ZipArray
翻转“Array
Array
”的轴,如:
[
["abc", "def", "ghi"],
["1234", "5678", "0123"],
["qwerty", "asdfg", "zxcvb"]
]
为:
[
["abc", "1234", "qwerty"],
["def", "5678", "asdgf"],
["ghi", "0123", "zxcvb"]
]
字典扩展名:
extension Dictionary {
init<S:SequenceType where S.Generator.Element == Element>(_ pairs:S) {
self.init()
var g = pairs.generate()
while let (k:Key, v:Value) = g.next() {
self[k] = v
}
}
}
然后你可以:
let returnedFromServer = [
"title" : ["abc", "def", "ghi"],
"time" : ["1234", "5678", "0123"],
"content":["qwerty", "asdfg", "zxcvb"]
]
let outputArray = map(ZipArray(returnedFromServer.values)) {
Dictionary(Zip2(returnedFromServer.keys, $0))
}