【问题标题】:Array to Set conversion taking 20 seconds - Swift 3数组到设置转换需要 20 秒 - Swift 3
【发布时间】:2017-03-17 11:47:11
【问题描述】:

为什么从字符串数组到 Set 的转换需要这么长时间?

我正在从 Core Data 读取数据并将获取的结果转换为字符串数组,然后从数组转换为集合。在模拟器中从数组到集合的转换大约需要 20 秒。

如果 Core Data 中没有数据,我将一个文本文件读入一个字符串数组,然后将该数组转换为一个集合。在这里进行转换只需不到 1 秒。

Core Data 中的数据与我将加载的文本文件保存到 Core Data 中的文本文件相同。那么我转换的两个字符串数组应该是一样的吧?

有什么帮助吗?

在约 20 秒内将数组转换为集合的函数

func coreData() {

    let appDelegate = UIApplication.shared.delegate as! AppDelegate // UIApplication.shared().delegate as! AppDelegate is now UIApplication.shared.delegate as! AppDelegate
    let context = appDelegate.persistentContainer.viewContext

    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Sowpods")
    request.returnsObjectsAsFaults = false

    do {
        let results = try context.fetch(request) as? [NSManagedObject] ?? []
        if results.count > 0 {
            print("Results fetched")

            // Load words from Core Data into wordSet
            let wordsArray = results.flatMap { $0.value(forKey: "words") as? String }

            let startTime = CFAbsoluteTimeGetCurrent()
            print("Putting fetched results from Array into Set")
            print("Words in array: \(wordsArray.count)")

            wordSet = Set(wordsArray.map { $0 }) /////// ~20 Seconds ///////////

            let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
            print("Time to put fetched results into wordSet: \(timeElapsed) s")

        } else {
            print("No results fetched from Core Data")
            // Read Dictionary

            wordSet = self.readDictionary(dictionaryFileName: "sowpods", dictionaryFileExtension: "txt")

            // Load words in dictionary into Core Data
            for word in wordSet {
                let newWord = NSEntityDescription.insertNewObject(forEntityName: "Sowpods", into: context)
                newWord.setValue(word, forKey: "words")
            }
            do {
                try context.save()
            } catch {
                print("Failed to save words")
            }
        }
    } catch {
        print("Couldn't fetch results")
    }
}

func readDictionary(dictionaryFileName: String, dictionaryFileExtension: String) -> Set<String> {
    print("Loading Dictionary")
    var wordsArray: [String] = []
    do {
        // This solution assumes  you've got the file in your bundle
        if let path = Bundle.main.path(forResource: dictionaryFileName, ofType: dictionaryFileExtension){
            let data = try String(contentsOfFile:path, encoding: String.Encoding.utf8)
            wordsArray = data.components(separatedBy: .newlines)
        }
    } catch let err as NSError {
        // do something with Error
        print(err)
    }

    let startTime = CFAbsoluteTimeGetCurrent()
    //print("Loading Dictionary")
    print("Words in array: \(wordsArray.count)")

    let dictionarySet = Set(wordsArray.map { $0 }) /////// < 1 Seconds ///////////

    let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
    print("Time to load dictionary Array into Set: \(timeElapsed) s")


    print("Done Loading Dictionary")
    return dictionarySet
}

快速转换记录

  • 没有从 Core Data 获取结果
  • 正在加载字典
  • 数组中的单词:267627
  • 将字典数组加载到集合中的时间:0.7359259724617 秒
  • 完成加载字典

缓慢转换的日志

  • 已获取结果
  • 将从 Array 获取的结果放入 Set 中
  • 数组中的单词:267627
  • 将获取的结果放入 wordSet 的时间:18.0488159656525 秒

【问题讨论】:

  • Set(wordsArray) 怎么样?
  • 使用returns​Distinct​Results for the coreData
  • @Lu_ 不,同时使用wordSet = Set(wordsArray)
  • 是的 - 你真的不想那样做。如果您想查看某个词是否存在,只需写一个NSFetchRequest 并计算一下。听起来像是另一个问题!
  • 你为什么在这里申请.map{$0}?这对于将 Array 转换为 Set 不是必需的。但是,它迫使您制作数组的副本。此外,虽然可能很小,但您在一种情况下直接分配给属性,在另一种情况下直接分配给局部变量。如果wordSet 包含didSet,那将是一个明显的区别。

标签: ios arrays swift core-data set


【解决方案1】:

会不会是你从数据库中获取的字符串有尾随空格?

这可能会使它们比文本文件中的长得多,从而导致 Set 的散列算法更努力地工作并可能发生冲突。

当转换为 Set 时,我通过在 238k 单词的单词列表中添加 40 个空格来测量时间增加了 3 倍。有了更多的空格和/或不同的词,这可以解释部分(如果不是全部)你得到的 20 倍差异。

或者,也许,带有关键字“words”的字典值每条记录包含一个以上的单词(顾名思义),这也会导致数组中的字符串更大,并且可能在集合中重复更少。

您应该将文件的 dictionarySet 中的元素数量与数据库的 wordSet 进行比较。我怀疑由于某种原因(这也可以解释时差),基于文件的集合中的条目可能会少得多。

【讨论】:

  • 谢谢,这两个数组之间一定有一些细微的差别,尽管两者都没有重复或尾随空格。我将创建核心数据NSEntityDescription.insertNewObject 的代码更改为遍历数组而不是集合。然后,当我在下次运行时重新读取核心数据时,它会在
猜你喜欢
  • 2021-07-25
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多