将结构属性转换为字典的更有效方法 [英] More efficient way for converting structure properties into dictionary

查看:36
本文介绍了将结构属性转换为字典的更有效方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找从结构创建字典的最有效方法.经过细致的研究,我发现了一种通过初始化所有属性来转换它的简便方法:

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆