swift 阵法内含太慢太快

qjp7pelc  于 2022-11-28  发布在  Swift
关注(0)|答案(3)|浏览(94)

我一直在将我在Java(Android)中使用的一个算法移植到Swift(iOS)中,在Swift版本上遇到了一些速度问题。
基本思想是有深度的对象(注解树),我可以通过匹配隐藏对象的列表来隐藏和显示数据集中的回复。

Top
- Reply 1
- - Reply 2
- - Reply 3
- Reply 4

并且在从数据集中隐藏之后

Top
- Reply 1
- Reply 4

我从Java转换的相关方法如下

//Gets the "real" position of the index provided in the "position" variable. The comments array contains all the used data, and the hidden array is an array of strings that represent items in the dataset that should be skipped over.

    func getRealPosition(position: Int)-> Int{

        let hElements = getHiddenCountUpTo(location: position)
        var diff = 0
        var i = 0
        while i < hElements {
            diff += 1
            if(comments.count > position + diff && hidden.contains(comments[(position + diff)].getId())){
                i -= 1
            }
            i += 1
        }
        return position + diff
    }

    func getHiddenCountUpTo(location: Int) -> Int{
        var count = 0
        var i = 0
        repeat {
            if (comments.count > i && hidden.contains(comments[i].getId())) {
                count += 1
            }
            i += 1
        } while(i <= location && i < comments.count)
        return count
    }

它与UITableViewController一起使用,以树的形式显示注解。
在Java中,使用array.contains足够快,不会导致任何延迟,但Swift版本在调用heightForRowAt和填充单元格时多次调用getRealPosition函数,导致延迟增加,因为更多的注解id被添加到“隐藏”数组中。
有没有什么方法可以提高数组“contains”查找的速度(可能使用不同类型的集合)?我对应用程序进行了分析,“contains”是占用时间最多的方法。
谢谢你

2izufjch

2izufjch1#

Java和Swift都必须遍历数组中包含的所有元素。随着数组变大,这会变得越来越慢。
Java的表现更好并没有什么先验的理由,因为它们都使用完全相同的算法。然而,字符串在每种语言中的实现方式都非常不同,这可能会使Swift中的字符串比较成本更高。
在任何情况下,如果字符串比较使您的速度变慢,那么您必须避免它。

简单修复:使用Set

如果你想要简单的性能提升,你可以用一个字符串集合来代替一个字符串数组。Swift中的集合是用一个哈希表来实现的,这意味着你期望的是常数时间查询。在实践中,这意味着对于大的集合,你会看到更好的性能。

var hiddenset Set<String> = {}
    for item in hidden {
      strset.insert(item)
    }

为获得最佳性能:使用位集

但是,您应该能够比集合做得更好。

hidden.contains(comments[i].getId()))

如果你总是以这种方式访问hidden,那么这意味着你所拥有的是一个从整数(i)到布尔值(true或false)的Map。
然后您应该执行以下操作...

import Bitset;

    let hidden = Bitset ();
    // replace hidden.append(comments[i].getId())) by this:
    hidden.add(i)
    // replace hidden.contains(comments[i].getId())) by this:
    hidden.contains(i)

然后您的代码将真正飞起来!
要在Swift中使用快速BitSet实现,请在Package.swift中包含以下内容(它是自由软件):

import PackageDescription

    let package = Package(
        name: "fun",
        dependencies: [
       .Package(url: "https://github.com/lemire/SwiftBitset.git",  majorVersion: 0)
        ]
    )
cx6n0qe3

cx6n0qe32#

我认为您需要realPosition来从tableview中某行上的tap链接到源数组?
1)创建第二个数组,其中只包含tableViewDataSource的数据
复制所有可见的元素到这个新的数组。创建一个特殊的ViewModel作为类或更好的结构,它只有必要的数据显示在tableview中。在这个新的ViewModel中保存realdataposition也作为值。现在你有一个到源数组的反向链接
2)则仅从新数据源填充此TableView
3)更多地了解swift中的functional programming-在那里你可以更好地学习数组,例如:

var array1 = ["a", "b", "c", "d", "e"]
let array2 = ["a", "c", "d"]
array1 = array1.filter { !array2.contains($0) }

或者在您的情况下:

let newArray = comments.filter{ !hidden.contains($0.getId()) }

或枚举以创建视图模型

struct CommentViewModel {
  var id: Int
  var text: String
  var realPosition: Int
}

let visibleComments: [CommentViewModel] = comments
   .enumerated()
   .map { (index, element) in
      return CommentViewModel(id: element.getId(), text: element.getText(), realPosition: index)
   }
   .filter{ !hidden.contains($0.id) }
gijlo24d

gijlo24d3#

firstIndex(of:)!= nil比contains()快得多

  • 这只是一个备忘录,因为帖子很旧 *

相关问题