2

我不明白数组方法indexOfObject:inSortedRange:options:usingComparator:

更具体地说,indexOfObject财产。

根据文档,传入的值应该是An object for which to search in the array. 但这没有任何意义.. 如果我已经引用了该对象,我为什么要在数组中搜索它?这是否意味着对象类型?

我有一个对象数组,我所拥有的只是这些对象的一个​​属性。IE。我有一系列汽车,当我的汽车 ID 为 12345 时,我需要找到汽车对象。

我会将什么传递给该indexOfObject属性的方法?这是我正在尝试的

   MyCarObject *searchObject;
   NSUInteger findIndex = [sortedArray indexOfObject:searchObject
                                       inSortedRange:searchRange
                                             options:NSBinarySearchingFirstEqual
                                     usingComparator:^(id obj1, id obj2)
                              {
                                return [obj1 compare:obj2];
                              }];

但这显然不会获得基于 ID 的对象.. 它似乎会给我我已经引用过的属性的索引,这似乎毫无意义..

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

4

4 回答 4

2

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

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

  • NSArrays 方法- (NSArray *)filteredArrayUsingPredicate:和相应的NSPredicate(有很多关于 SO 和教程的问题)
  • 自己的循环将您想要的任何属性与任何值进行比较(在您的情况下,对象的汽车 ID 与您正在搜索汽车的 ID)
于 2013-09-24T14:26:21.213 回答
1

It is possible to bludgeon this API into doing what you want, although I do not really advocate this method. If you pass in the key you wish to search for, that will be passed into the comparator along with the element being compared against. However, the order in which these arguments are passed changes so you need to inspect the class of the comparator arguments at runtime to in order to differentiate them and perform your comparison.

- (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];
}

This does function, however it feels quite awkward, plus I am not confident of the performance impact when performing large searches (although it is surely still less than an O(n) search). Perhaps you could build a nicer method on top of these which hides the kludge factor.

于 2014-03-18T13:54:45.863 回答
0

compare:方法(您用于二进制搜索比较器)根据对象的不同意味着不同的事情。NSString例如,将 compare 实现为词法比较。因此,如果您有一个 sorted NSArrayNSString那么您将得到的是与输入字符串匹配的字符串列表中的索引(或者NSNotFound如果不在数组中)。

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

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

于 2016-01-13T15:32:09.413 回答
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
于 2015-10-15T15:23:30.760 回答