将结构属性转换为字典的更有效方法 [英] More efficient way for converting structure properties into dictionary
问题描述
我一直在寻找从结构创建字典的最有效方法.经过细致的研究,我发现了一种通过初始化所有属性来转换它的简便方法:
I was looking for most efficient way for creating dictionary from structures. After small research I found easy way for converting it via initialising all properties like that :
func toDictionary() -> [String : AnyObject] {
let dictionary: [String: AnyObject] = ["firstProperty" : sth, "secondProperty" : "sth2"]
return dictionary
}
但是等等.我是否必须在结构中每次都初始化它?他们可能有很多财产..这让我思考.如果我可以通过类的循环获得属性,该怎么办.是的,可以使用 Mirror
反射.经过一段时间的尝试,我明白了—而不是上面的功能,我编写了实现一个功能的协议.
But wait.. Do I have to initialise it every time in my structures ? They might have a loot of properties.. It gave me to think. What if I could get properties though the looping of the class somehow. Yeah, it is possible using Mirror
reflection. After a while of trying I've got it - instead of function above I've written protocol which implements one function.
protocol Mirrorable {
func toDictionary() -> [String : AnyObject]
}
然后在我的结构中,我可以简单地使用:
Then in my structure I can simply use :
extension MyStructure/MyClass : Mirrorable {
func toDictionary() -> [String : AnyObject] {
let reflection = Mirror(reflecting: self).children
var dictionary = [String : AnyObject]()
for (label, value) in reflection {
dictionary[label!] = value as AnyObject
}
return dictionary
}
}
好奇心并没有让我停止思考.哪种方法更有效?
Curiosity does not let me to stop thinking about it. Which way would be more efficient ?
推荐答案
TLDR
直接转换速度更快,但是由于大多数情况下您不必将1.000.000+个结构转换为字典,因此我将使用协议扩展.
TLDR
Direct conversion is faster but since most cases you won't have to convert 1.000.000+ structs to dictionary I'd use a protocol extension.
我创建了一个Mac cmd line应用程序来测试时间,并且正如预期的那样,直接转换更快.这很明显,因为编译器可以对其进行优化,并且代码本身很简单.使用反射时,您会创建大量额外的结构和变量,还增加了一些开销.
I created a Mac cmd line app to test the time and as expected the direct conversion is faster. This is kind of obvious since the compiler could optimize it and since the code itself is simple. When using reflection you create a bunch of extra structures and variables, also add some overhead.
尽管直接转换更快,但我认为在大多数实际情况下,使用协议扩展方法会很好,因为它很容易在您的代码库中采用.您必须记住的一件事是,使用反射的代码未考虑嵌套对象,这会使该方法变得更慢,并且如果您使用递归会产生更大的开销.
Even though the direct conversion is faster, I think in most real cases would be fine to use the protocol extension approach since it's easy to adopt in your code base. One thing you must have in mind is that your code using reflection is not considering nested objects, this would make the method even slower and also if you used recursion would generate a bigger overhead.
以下是3次执行的结果,这些执行将1.000.000结构编码为字典:
Here are the results for 3 executions encoding 1.000.000 structs to a dictionary:
-
Apple LLVM 8.1-代码生成
Apple LLVM 8.1 - Code Generation
- 优化级别:-Ofast
Swift编译器-代码生成:
Swift Compiler - Code Generation:
- 优化级别:-O-整个模块的优化
使用S1(直接转换)执行1000000次的时间:0.569061994552612
Time for 1000000 executions with S1(direct conversion): 0.569061994552612
使用S2(结构扩展+协议)执行1000000次的时间:7.68360501527786
Time for 1000000 executions with S2(struct extension + protocol): 7.68360501527786
使用S3(协议扩展)执行1000000次的时间:7.71803396940231
Time for 1000000 executions with S3(protocol extension): 7.71803396940231
使用S1(直接转换)执行1000000次的时间:0.500779032707214
Time for 1000000 executions with S1(direct conversion): 0.500779032707214
使用S2(结构扩展+协议)执行1000000次的时间:7.58478999137878
Time for 1000000 executions with S2(struct extension + protocol): 7.58478999137878
使用S3(协议扩展)执行1000000次的时间:7.73368299007416
Time for 1000000 executions with S3(protocol extension): 7.73368299007416
使用S1(直接转换)执行1000000次的时间:0.492152035236359
Time for 1000000 executions with S1(direct conversion): 0.492152035236359
使用S2(结构扩展+协议)执行1000000次的时间:7.81585901975632
Time for 1000000 executions with S2(struct extension + protocol): 7.81585901975632
使用S3(协议扩展)执行1000000次的时间:7.41855001449585
Time for 1000000 executions with S3(protocol extension): 7.41855001449585
构建设置
-
Apple LLVM 8.1-代码生成
Build settings
Apple LLVM 8.1 - Code Generation
- 优化级别:-Ofast
Swift编译器-代码生成:
Swift Compiler - Code Generation:
- 优化级别:-Onone
使用S1(直接转换)执行1000000次的时间:2.92627400159836
Time for 1000000 executions with S1(direct conversion): 2.92627400159836
使用S2(结构扩展+协议)执行1000000次的时间:9.25952398777008
Time for 1000000 executions with S2(struct extension + protocol): 9.25952398777008
使用S3(协议扩展)执行1000000次的时间:9.19355899095535
Time for 1000000 executions with S3(protocol extension): 9.19355899095535
使用S1(直接转换)执行1000000次的时间:2.9830749630928
Time for 1000000 executions with S1(direct conversion): 2.9830749630928
使用S2(结构扩展+协议)执行1000000次的时间:9.06750500202179
Time for 1000000 executions with S2(struct extension + protocol): 9.06750500202179
使用S3(协议扩展)执行1000000次的时间:8.77240401506424
Time for 1000000 executions with S3(protocol extension): 8.77240401506424
使用S1(直接转换)执行1000000次的时间:2.81389397382736
Time for 1000000 executions with S1(direct conversion): 2.81389397382736
使用S2(结构扩展+协议)执行1000000次的时间:8.84287703037262
Time for 1000000 executions with S2(struct extension + protocol): 8.84287703037262
使用S3(协议扩展)执行1000000次的时间:9.08754301071167
Time for 1000000 executions with S3(protocol extension): 9.08754301071167
构建设置
-
Apple LLVM 8.1-代码生成
Build settings
Apple LLVM 8.1 - Code Generation
- 优化级别:-O0
Swift编译器-代码生成:
Swift Compiler - Code Generation:
- 优化级别:-O-整个模块的优化
使用S1(直接转换)执行1000000次的时间:0.533200979232788
Time for 1000000 executions with S1(direct conversion): 0.533200979232788
使用S2(结构扩展+协议)执行1000000次的时间:8.15365797281265
Time for 1000000 executions with S2(struct extension + protocol): 8.15365797281265
使用S3(协议扩展)执行1000000次的时间:7.80043601989746
Time for 1000000 executions with S3(protocol extension): 7.80043601989746
使用S1(直接转换)执行1000000次的时间:0.509769976139069
Time for 1000000 executions with S1(direct conversion): 0.509769976139069
使用S2(结构扩展+协议)执行1000000次的时间:7.76911997795105
Time for 1000000 executions with S2(struct extension + protocol): 7.76911997795105
使用S3(协议扩展)执行1000000次的时间:8.00845402479172
Time for 1000000 executions with S3(protocol extension): 8.00845402479172
使用S1(直接转换)执行1000000次的时间:0.532546997070312
Time for 1000000 executions with S1(direct conversion): 0.532546997070312
使用S2(结构扩展+协议)执行1000000次的时间:7.99552202224731
Time for 1000000 executions with S2(struct extension + protocol): 7.99552202224731
使用S3(协议扩展)执行1000000次的时间:7.86273497343063
Time for 1000000 executions with S3(protocol extension): 7.86273497343063
构建设置
-
Apple LLVM 8.1-代码生成
Build settings
Apple LLVM 8.1 - Code Generation
- 优化级别:-O0
Swift编译器-代码生成:
Swift Compiler - Code Generation:
- 优化级别:-Onone
使用S1(直接转换)执行1000000次的时间:2.90398299694061
Time for 1000000 executions with S1(direct conversion): 2.90398299694061
使用S2(结构扩展+协议)执行1000000次的时间:9.62662398815155
Time for 1000000 executions with S2(struct extension + protocol): 9.62662398815155
使用S3(协议扩展)执行1000000次的时间:9.55038601160049
Time for 1000000 executions with S3(protocol extension): 9.55038601160049
使用S1(直接转换)执行1000000次的时间:2.98312002420425
Time for 1000000 executions with S1(direct conversion): 2.98312002420425
使用S2(结构扩展+协议)执行1000000次的时间:9.62088203430176
Time for 1000000 executions with S2(struct extension + protocol): 9.62088203430176
使用S3(协议扩展)执行1000000次的时间:8.82720899581909
Time for 1000000 executions with S3(protocol extension): 8.82720899581909
使用S1(直接转换)执行1000000次的时间:2.77569997310638
Time for 1000000 executions with S1(direct conversion): 2.77569997310638
使用S2(结构扩展+协议)执行1000000次的时间:8.83749902248383
Time for 1000000 executions with S2(struct extension + protocol): 8.83749902248383
使用S3(协议扩展)执行1000000次的时间:8.76373296976089
Time for 1000000 executions with S3(protocol extension): 8.76373296976089
代码:
import Foundation // Direct conversion to dictionary struct S1 { var a: Int var b: Int var c: Int func toDictionary() -> [String : AnyObject] { let dictionary: [String: AnyObject] = [ "a":a as AnyObject, "b":b as AnyObject, "c":c as AnyObject ] return dictionary } } // Conversion using struct extension + protocol protocol Mirrorable1 { func toDictionary() -> [String : AnyObject] } struct S2 { var a: Int var b: Int var c: Int } extension S2: Mirrorable1 { func toDictionary() -> [String : AnyObject] { let reflection = Mirror(reflecting: self).children var dictionary = [String : AnyObject]() for (label, value) in reflection { dictionary[label!] = value as AnyObject } return dictionary } } // Conversion using protocol extension protocol Mirrorable2 { func toDictionary() -> [String : AnyObject] } extension Mirrorable2 { func toDictionary() -> [String : AnyObject] { let reflection = Mirror(reflecting: self).children var dictionary = [String : AnyObject]() for (label, value) in reflection { dictionary[label!] = value as AnyObject } return dictionary } } struct S3: Mirrorable2 { var a: Int var b: Int var c: Int } let listOfExecutions = [1_000_000, 1_000_000, 1_000_000] for executions in listOfExecutions { // S1 var start = CFAbsoluteTimeGetCurrent() for i in 0..<executions { S1(a: 0, b: 1, c: 2).toDictionary() } print("Time for \(executions) executions with S1(direct conversion):") print(CFAbsoluteTimeGetCurrent() - start) // S2 start = CFAbsoluteTimeGetCurrent() for i in 0..<executions { S2(a: 0, b: 1, c: 2).toDictionary() } print("Time for \(executions) executions with S2(struct extension + protocol):") print(CFAbsoluteTimeGetCurrent() - start) // S3 start = CFAbsoluteTimeGetCurrent() for i in 0..<executions { S3(a: 0, b: 1, c: 2).toDictionary() } print("Time for \(executions) executions with S3(protocol extension):") print(CFAbsoluteTimeGetCurrent() - start) }
这篇关于将结构属性转换为字典的更有效方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!