我不理解数组方法indexOfObject:inSortedRange:options:usingComparator:
更具体地说,indexOfObject
属性。
根据文档传入的值应为An object for which to search in the array.
但这没有意义..如果我已经有了对象的引用,为什么我会在数组中搜索它?这是否意味着对象类型?
我有一个对象数组,而我拥有的只是这些对象的属性。即。我有一系列汽车,当我的汽车ID为12345时,我需要找到汽车对象。
我将传递给indexOfObject
属性的方法?这是我正在尝试的
MyCarObject *searchObject;
NSUInteger findIndex = [sortedArray indexOfObject:searchObject
inSortedRange:searchRange
options:NSBinarySearchingFirstEqual
usingComparator:^(id obj1, id obj2)
{
return [obj1 compare:obj2];
}];
但是这显然不会得到一个基于ID的对象..看起来它会给我一个我已经引用的属性的索引,这似乎毫无意义....
如果这不是正确的方法,那么我应该使用什么?我需要对对象数组使用二进制搜索并拉出对该对象的引用。我所拥有的只是一个可以比较的属性。
答案 0 :(得分:2)
此方法返回给定数组中对象的索引,这有时非常有用。使用isEqual:
方法(默认情况下比较指针)比较数组中的对象。这就是该方法无法知道您希望使用某些自定义属性进行比较的原因。
要使用您自己的属性在数组中查找特定对象,请使用
NSArray
方法- (NSArray *)filteredArrayUsingPredicate:
和相应的NSPredicate
(关于SO的问题和教程有很多问题)答案 1 :(得分:0)
如果您传入要搜索的键,则会将该元素与要比较的元素一起传递到比较器中。但是,传递这些参数的顺序会发生变化,因此您需要在运行时检查比较器参数的类,以便区分它们并执行比较。
- (BWCProductCategory *)categoryForID:(NSNumber *)ID categories:(NSArray *)categories {
NSRange searchRange = NSMakeRange(0, categories.count);
NSUInteger index = [categories indexOfObject:ID
inSortedRange:searchRange
options:NSBinarySearchingFirstEqual
usingComparator:^NSComparisonResult(id obj1, id obj2) {
if ([obj1 isKindOfClass:[BWCProductCategory class]]) {
return [[(BWCProductCategory *)obj1 categoryID] compare:obj2];
} else {
return [obj1 compare:[(BWCProductCategory *)obj2 categoryID]];
}
}];
return (index == NSNotFound) ? nil : categories[index];
}
这确实有用,但感觉很尴尬,而且我对执行大型搜索时的性能影响没有信心(尽管它肯定还不及O(n)搜索)。也许你可以在这些方法之上构建一个更好的方法来隐藏kludge因素。
答案 2 :(得分:0)
我为Swift的Array
创建了一个扩展,以便以这种方式使Swift非常干净。
import Foundation
extension Array where Element: AnyObject {
public func indexOfObject<T: AnyObject>(obj: T, options opts: NSBinarySearchingOptions, usingComparator cmp: (T, Element) -> NSComparisonResult) -> Int {
return (self as NSArray).indexOfObject(obj, inSortedRange: NSRange(0..<count), options: opts, usingComparator: { (a: AnyObject, b: AnyObject) -> NSComparisonResult in
if a === obj {
return cmp(a as! T, b as! Element)
} else {
var result = cmp(b as! T, a as! Element)
if result == .OrderedDescending {
result = .OrderedAscending
} else if result == .OrderedAscending {
result = .OrderedDescending
}
return result
}
})
}
}
以下是一个示例用法:
class ItemWithProperty {
var property: Int
init(property: Int) {
self.property = property
}
}
let listOfItems = [ItemWithProperty(property: 1),
ItemWithProperty(property: 20),
ItemWithProperty(property: 30),
ItemWithProperty(property: 45),
ItemWithProperty(property: 45),
ItemWithProperty(property: 45),
ItemWithProperty(property: 60),
ItemWithProperty(property: 77),
]
let indexOf20 = listOfItems.indexOfObject(20, options: .FirstEqual) { number, item in
number.compare(item.property)
}
// returns 1
let indexOf25 = listOfItems.indexOfObject(25, options: .FirstEqual) { number, item in
number.compare(item.property)
}
indexOf25 == NSNotFound
// comparison is true, number not found
let indexOfFirst45 = listOfItems.indexOfObject(45, options: .FirstEqual) { number, item in
number.compare(item.property)
}
// returns 3
let indexOfLast45 = listOfItems.indexOfObject(45, options: .LastEqual) { number, item in
number.compare(item.property)
}
// returns 5
let indexOf77 = listOfItems.indexOfObject(77, options: .FirstEqual) { number, item in
number.compare(item.property)
}
// returns 7
答案 3 :(得分:0)
compare:
方法(您用于二进制搜索比较器)根据对象的不同而不同。例如,NSString
将比较实现为词法比较。所以,如果你有一个NSArray
的{{1}},那么你将得到的是与输入字符串匹配的字符串列表中的索引(如果不在数组中,则为NSString
)。
对于您的对象类型(NSNotFound
),您将实现MyCarObject
的定义以确定compare:
的相对顺序。然后,您可以构造MyCarObject
的新实例,并使用此方法确定等效对象(由MyCarObject
确定)是否已在列表中。
请注意,此方法执行二进制搜索,因此必须使用与搜索它相同的比较器对数组进行排序。您可以使用compare:
来查找插入新元素的索引,以便对列表进行排序。