Ios 过滤包含大量对象的数组的唯一名称
我目前正在获取大量包含街道名称和坐标的对象。返回的数组大约有22000个对象,我们想要的结果数组大约有4000个,其余的都是重复的。这类数据的问题是,获取的对象可能具有相同的名称,但坐标不同,我只对基于唯一名称获取对象感兴趣。如果有多个具有相同名称的对象,我只希望保留第一个对象 到目前为止,我一直试图通过比较名字在街上兜圈子。我宁愿使用Ios 过滤包含大量对象的数组的唯一名称,ios,swift,performance,Ios,Swift,Performance,我目前正在获取大量包含街道名称和坐标的对象。返回的数组大约有22000个对象,我们想要的结果数组大约有4000个,其余的都是重复的。这类数据的问题是,获取的对象可能具有相同的名称,但坐标不同,我只对基于唯一名称获取对象感兴趣。如果有多个具有相同名称的对象,我只希望保留第一个对象 到目前为止,我一直试图通过比较名字在街上兜圈子。我宁愿使用过滤器或其他更高效的解决方案 我的结构 到目前为止我的代码 DataManager.shared.getStreetNames{(街道)位于 变量名称数组:[St
过滤器
或其他更高效的解决方案
我的结构
到目前为止我的代码
DataManager.shared.getStreetNames{(街道)位于
变量名称数组:[StreetName]=[]
街道名称{
let name=streetName.name
如果namesArray.count==0{
namesArray.append(streetName)
}如果namesArray.contains(其中:{$0.name==name}){
/*不要添加*/
}否则{
namesArray.append(streetName)
}
}
self.streetNames=namesArray.sorted(按:{$0.name<$1.name})
self.filteredStreetNames=self.streetNames
OperationQueue.main.addOperation{
self.streetTableView.reloadData()
}
}
这个代码块可以工作,但在iPhoneX上运行大约30秒。这太慢了。有什么想法吗?我想如果你分析一下,你会发现
排序花费的时间最多。我找不到正式的注释,但底层实现很可能是快速排序,当数组已经排序(或数组按相反顺序排序)时,它的复杂性最差
快速排序的平均案例复杂度是O(n logn),但在最坏的情况下是O(n2)
我认为应该实现插入排序,或者更准确地说,总是将新元素插入到已排序的位置。这将使整个函数的复杂度降低到O(n)
伪代码:
- 取街名
- 每个街道的名称
- 在现有数组中查找街道名称的位置(我建议进行二进制搜索,因为数组已经排序)
- 如果街道名称已存在,请跳过
- 如果名称不存在,请插入它
结果应该是唯一街道名称的排序数组,要求每个名称只读取和插入一次。我的看法是:
// Given an array of elements (here just Ints):
let array = (0..<1000).map { _ in Int(arc4random_uniform(100)) }
// Sort it:
let sorted = array.sorted()
// Define an empty result (array of elements) which is a variable
// and which gets modified in the subsequent reduce function:
var unique: [Int] = []
// A tailored reduce which depends on a sorted array and appends
// to the result IFF that element is not the last in result:
let result = sorted.reduce(into: unique) { (result, element) in
if let last = result.last, last == element {
} else {
result.append(element)
}
}
控制台上的输出示例:
控制台
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
@MartinR通过使用集合解决了这个问题
我的新更新结构
我的新更新代码
DataManager.shared.getStreetNames{(returnedNameset)位于
变量名称数组:[StreetName]=数组(返回的名称集)
self.streetNames=namesArray.sorted(按:{$0.name<$1.name})
self.filteredStreetNames=self.streetNames
OperationQueue.main.addOperation{
self.streetTableView.reloadData()
}
}
结果:
使用Set
将处理时间从30秒增加到了0.4秒。我建议重新打开此问题,建议的重复地址将删除重复地址,但没有解决效率问题。为什么删除代码的排序部分?还原了编辑器,使用将直接从数据库返回街道排序数组的查询。使用前向迭代器或使用定制的reduce
函数很容易删除重复项。这就是我的意思:如果数组已经“某种程度上”排序,这不是快速排序的最佳选择,那么shuffle
然后quick sort
然后reduce
怎么样?我也喜欢这个想法,但是要想弄清楚如何将这个伪代码转换成代码,我会很困难。任何指针?在建议的中,提供了删除重复项的最有效方法。相比之下,对数组进行排序的时间可以忽略不计。Swift使用introsort(快速排序的一种变体),compare。已排序的数组是否为最坏情况取决于枢轴元素的选择。Swift使用第一、中间、最后一个元素的中间值。@vadian-这不是比较相等的对象吗?本例中的对象是唯一的,但某些值可能相同…您对==
的实现是错误的:不同的字符串可以具有相同的哈希值。您有什么建议来解决此问题吗?到目前为止,我对此没有任何问题,但您是正确的@MartinRIf等式仅基于街道名称,然后返回lhs.name==rhs.name
顺便说一句,使类型本身可散列并不完全是我在中建议的,但要保持迄今为止在集中看到的所有名称,它工作得非常好,我将编辑答案!真的,谢谢@MartinR
DataManager.shared.getStreetNames { (streets) in
var namesArray: [StreetName] = []
for streetName in streets {
let name = streetName.name
if namesArray.count == 0 {
namesArray.append(streetName)
} else if namesArray.contains(where: {$0.name == name }) {
/* Dont add */
} else {
namesArray.append(streetName)
}
}
self.streetNames = namesArray.sorted(by: {$0.name < $1.name})
self.filteredStreetNames = self.streetNames
OperationQueue.main.addOperation {
self.streetTableView.reloadData()
}
}
// Given an array of elements (here just Ints):
let array = (0..<1000).map { _ in Int(arc4random_uniform(100)) }
// Sort it:
let sorted = array.sorted()
// Define an empty result (array of elements) which is a variable
// and which gets modified in the subsequent reduce function:
var unique: [Int] = []
// A tailored reduce which depends on a sorted array and appends
// to the result IFF that element is not the last in result:
let result = sorted.reduce(into: unique) { (result, element) in
if let last = result.last, last == element {
} else {
result.append(element)
}
}
print(array)
struct StreetName: Hashable {
static func == (lhs: StreetName, rhs: StreetName) -> Bool {
return lhs.name == rhs.name
}
var hashValue: Int {
return name.hashValue
}
var name: String
var polyLine: CLLocationCoordinate2D
}
DataManager.shared.getStreetNames { (returnedNamesSet) in
var namesArray: [StreetName] = Array(returnedNamesSet)
self.streetNames = namesArray.sorted(by: {$0.name < $1.name})
self.filteredStreetNames = self.streetNames
OperationQueue.main.addOperation {
self.streetTableView.reloadData()
}
}