数组包含太慢 Swift
Array Contains Too Slow Swift
我一直在将我在 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 添加到 "hidden" 数组,导致延迟增加。
有什么方法可以提高数组 "contains" 查找的速度(可能使用不同类型的集合)?我对应用程序进行了分析,"contains" 是占用时间最多的方法。
谢谢
我认为您需要 realPosition 到 link 从点击表视图中的一行到源数组?
1) 为 tableViewDataSource 创建第二个数据数组
将所有可见元素复制到这个新数组中。创建一个特殊的 ViewModel 作为 class 或更好的结构,它只有必要的数据才能在 tableview 中显示。在这个新的 ViewModel 中保存 realdataposition 也作为值。现在你有一个返回link到源数组
2) 然后仅从新数据源填充此 TableView
3) 更多地查看 swift 中的 functional programming
- 在那里你可以更好地遍历数组,例如:
var array1 = ["a", "b", "c", "d", "e"]
let array2 = ["a", "c", "d"]
array1 = array1.filter { !array2.contains([=10=]) }
或者您的情况:
let newArray = comments.filter{ !hidden.contains([=11=].getId()) }
或枚举创建viewmodel
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([=12=].id) }
Java和Swift都必须遍历数组中包含的所有元素。随着数组变大,这会变得越来越慢。
Java 没有先验的理由表现得更好,因为它们都使用完全相同的算法。但是,字符串在每种语言中的实现方式非常不同,因此 Swift.
中的字符串比较可能会更加昂贵
无论如何,如果字符串比较让你变慢,那么你必须避免它。
轻松修复:使用集合
如果您想要简单的性能提升,您可以用一组字符串替换一个字符串数组。 Swift 中的集合是用散列 table 实现的,这意味着您希望进行恒定时间查询。实际上,这意味着对于大型集合,您会看到更好的性能。
var hiddenset Set<String> = {}
for item in hidden {
strset.insert(item)
}
为了获得最佳性能:使用 BitSet
但是你应该能够比一组更好。让我们看看您的代码
hidden.contains(comments[i].getId()))
如果您总是以这种方式访问 hidden
,那么这意味着您拥有的是从整数 (i
) 到布尔值(真或假)的映射。
那么你应该做以下事情...
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)
]
)
我一直在将我在 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 添加到 "hidden" 数组,导致延迟增加。
有什么方法可以提高数组 "contains" 查找的速度(可能使用不同类型的集合)?我对应用程序进行了分析,"contains" 是占用时间最多的方法。
谢谢
我认为您需要 realPosition 到 link 从点击表视图中的一行到源数组?
1) 为 tableViewDataSource 创建第二个数据数组
将所有可见元素复制到这个新数组中。创建一个特殊的 ViewModel 作为 class 或更好的结构,它只有必要的数据才能在 tableview 中显示。在这个新的 ViewModel 中保存 realdataposition 也作为值。现在你有一个返回link到源数组
2) 然后仅从新数据源填充此 TableView
3) 更多地查看 swift 中的 functional programming
- 在那里你可以更好地遍历数组,例如:
var array1 = ["a", "b", "c", "d", "e"]
let array2 = ["a", "c", "d"]
array1 = array1.filter { !array2.contains([=10=]) }
或者您的情况:
let newArray = comments.filter{ !hidden.contains([=11=].getId()) }
或枚举创建viewmodel
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([=12=].id) }
Java和Swift都必须遍历数组中包含的所有元素。随着数组变大,这会变得越来越慢。
Java 没有先验的理由表现得更好,因为它们都使用完全相同的算法。但是,字符串在每种语言中的实现方式非常不同,因此 Swift.
中的字符串比较可能会更加昂贵无论如何,如果字符串比较让你变慢,那么你必须避免它。
轻松修复:使用集合
如果您想要简单的性能提升,您可以用一组字符串替换一个字符串数组。 Swift 中的集合是用散列 table 实现的,这意味着您希望进行恒定时间查询。实际上,这意味着对于大型集合,您会看到更好的性能。
var hiddenset Set<String> = {}
for item in hidden {
strset.insert(item)
}
为了获得最佳性能:使用 BitSet
但是你应该能够比一组更好。让我们看看您的代码
hidden.contains(comments[i].getId()))
如果您总是以这种方式访问 hidden
,那么这意味着您拥有的是从整数 (i
) 到布尔值(真或假)的映射。
那么你应该做以下事情...
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)
]
)