使用 indexOfObject:inSortedRange:options:usingComparator:对数组进行



我不明白数组方法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 的对象。 它似乎会给我我已经引用的属性的索引,这似乎毫无意义......

如果这不是正确的方法,那么我应该使用什么? 我需要对对象数组使用二进制搜索并提取对该对象的引用。 而我所拥有的只是一个可以比较的属性。

此方法返回给定数组中对象的索引,这有时非常有用。数组中的对象使用isEqual:方法(默认情况下比较指针(进行比较。这就是该方法没有机会知道您希望使用某些自定义属性进行比较的原因。

要通过您自己的属性查找数组中的特定对象,请使用

  • NSArray的方法- (NSArray *)filteredArrayUsingPredicate:和相应的NSPredicate(有很多关于SO的问题和教程(
  • own循环将您想要的任何属性与任何值进行比较(对象的汽车ID与您在汽车中搜索汽车的ID相同(
可以把

这个 API 变成你想做的事,尽管我并不真正提倡这种方法。如果您传入要搜索的键,则该键将与要比较的元素一起传递到比较器中。但是,这些参数的传递顺序会发生变化,因此您需要在运行时检查比较器参数的类,以便区分它们并进行比较。

- (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因素。

我为 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

compare:方法(您用于二进制搜索比较器(根据对象表示不同的东西。 例如,NSString将比较实现为词法比较。因此,如果您有 NSString 的排序NSArray,那么您将返回的是与输入字符串匹配的字符串列表中的索引(如果不在数组中,则返回NSNotFound(。

对于你的对象类型(MyCarObject(,你将实现你的compare:定义来确定MyCarObject的相对顺序。然后你可以构造一个MyCarObject的新实例,并使用此方法来确定列表中是否已经有等效的对象(由compare:确定(。

请注意,此方法执行二进制搜索,因此必须使用用于搜索数组的同一比较器对数组进行排序。可以使用 NSBinarySearchingInsertionIndex 查找要插入新元素以保持列表排序的索引。

最新更新