【问题标题】:How to handle large strings in swift?如何快速处理大字符串?
【发布时间】:2018-03-01 12:08:16
【问题描述】:

我有这段代码,它需要很长时间才能快速执行? 每次迭代需要 1 秒来执行,为什么?

执行该循环时的 CPU 百分比为 97-98%,能量影响很高

这是代码

     var braces:Int = 1;
     var i:Int = startIndex;
     let jsFileChars = Array(javascriptFile);
      while(i < javascriptFile.count){   //count:1240265        
         if (braces == 0) {
              break;
         }                            
        if (jsFileChars[i] == "{"){     
             braces = braces+1;
         }else if (jsFileChars[i] == "}"){
              braces = braces-1;
         }
             i = i+1;
   }

这个循环的迭代速度很慢,为什么?

【问题讨论】:

  • 因为 120 万次迭代很多(?)。另外,你能定义“很多时间”吗?可接受的时间量是多少?
  • 我在项目中放了一个日志来打印大括号,我不知道为什么该日志每秒打印一次?
  • @MartinR 现在更新了,请查看它和它的 Xcode 项目以及它的执行时间非常糟糕。

标签: swift string performance


【解决方案1】:

循环很慢,因为确定 Swift stringcount 是 O(N) 运算,其中 N 是字符串中的字符数。 另见“Swift 编程语言”中的Counting Characters

注意

扩展字素簇可以由多个 Unicode 标量组成。这意味着不同的字符——以及同一字符的不同表示——可能需要不同数量的内存来存储。正因为如此,Swift 中的字符不会在字符串表示中占用相同数量的内存。因此,如果不遍历字符串以确定其扩展的字形簇边界,就无法计算字符串中的字符数。 ...

应该已经将javascriptFile.count 替换为jsFileChars.count 提高性能,因为数组的长度在 恒定的时间。

更好地直接迭代字符,而无需创建 数组:

var braces = 1
for char in javascriptFile {
    if char == "{" {
        braces += 1
    } else if char == "}" {
        braces -= 1
    }
}

遍历 UTF-16 视图甚至更快,因为 是 Swift 字符串(当前)用作内部存储的:

let openingBrace = "{".utf16.first!
let closingBrace = "}".utf16.first!

var braces = 1
for char in javascriptFile.utf16 {
    if char == openingBrace {
        braces += 1
    } else if char == closingBrace {
        braces -= 1
    }
}

【讨论】:

  • 哇!马丁那太棒了。你是天才。
【解决方案2】:

当您考虑在 Swift 中迭代集合时(字符串是字符的集合),有时使用 reduce() 会更快。你可以像这样使用reduce() 来实现你的大括号计数器:

let braces = javascriptFile.reduce(0, { count, char in
    switch char {
    case "{": return count + 1
    case "}": return count - 1
    default: return count
    }
})

我不知道这是否会比在您的情况下使用 for 循环更快,但可能值得一试。如果没有别的,这样写的意图就很清楚了。

【讨论】:

  • 我喜欢它评估为 constant。 - 但我相当确定 reduce() 总是按顺序而不是并行处理元素。在我的简单测试中,reduce 和 for 循环之间的时间没有显着差异。
  • @MartinR 想一想,我相信你是对的——reduce() 采用的闭包无法组合来自多个 reduce() 操作的结果——@987654328 @ 通常用于将多个 map() 操作的结果组合成一个结果。即便如此,我还是喜欢这里的reduce() 选项,只是因为它使意图非常明确。我想您可以划分字符串并使用map() 计算每个子字符串中的大括号,然后使用reduce() 组合结果。
  • reduce() 唯一不可能做到的是“提前返回”,就像问题中的if (braces == 0) { break }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-25
  • 2021-04-17
  • 1970-01-01
  • 2015-02-07
  • 2020-02-28
  • 2020-04-09
相关资源
最近更新 更多