sortedArrayUsingComparator方法是如何实现的?

时间:2015-02-05 15:38:28

标签: ios objective-c cocoa-touch sorting compare

我试图重写Objective-C中的官方sortedArrayUsingComparator:方法。我怎样才能做到这一点?

NSArray类中,元素如何实际存储在数组中? for循环中的类型(代码:type?)是什么? Objective-C中似乎不存在泛型。 compare:方法如何工作?

- (NSArray *)recentQuestions {
    return [questions sortedArrayUsingComparator: ^(id obj1, id obj2) {
        Question *q1 = (Question *)obj1; 
        Question *q2 = (Question *)obj2; 
        return [q2.date compare: q1.date];
}]; }

//class NSArray

//? NSArray* selfArray = @[];
-(...) sortedArrayUsingComparator : (void (^)(id obj1, id obj2) ) blockName{
    for ( int i=0; i<selfArray.count-1; i++){ 
        for ( int j=i+1; j<selfArray.count; j++){ 
            type? *bigger = blockName(selfArray[i], selfArray[j]);          
            //move items if j>i
            if (bigger isEqual:selfArray[j]) {
                int tempValue = newArray[i];
                newArray[i] = newArray[j];
                newArray[j] = tempValue;
            }
        }
    }
}

2 个答案:

答案 0 :(得分:1)

我会尝试回答你提出的问题。


在NSArray类中,如何实际存储添加到数组中的元素?

我认为你在询问如何添加新元素或修改NSArray中元素的顺序。这是不可能的。如果需要改变数组的内容,则应该使用NSMutableArray。使用NSMutableArray,可以使用以下内容:

id tempValue = newArray[i];
newArray[i] = newArray[j];
newArray[j] = tempValue;

for-loop中的类型(代码:type?)是什么?目标c中似乎不存在Generics

您应该期望的类型是您从块中获得的任何返回类型。在您的情况下,您指定的块具有void返回类型,这意味着您确实不应该尝试从其结果中分配变量。下面,您将看到返回类型应列为NSComparisonResult

在我对第一个问题的回答中,您可能已经注意到在objective-c中如何处理泛型指针:id。每个非原始对象都可以保存在id变量中。


比较方法如何运作?

-(...) sortedArrayUsingComparator : (void (^)(id obj1, id obj2) ) blockName{

您应该为sortedArrayUsingComparator指定返回类型。我建议NSArray。您的块的返回类型也应为NSComparisonResult

-(NSArray *) sortedArrayUsingComparator : (NSComparisonResult (^)(id obj1, id obj2) ) blockName{

现在,当您调用块时,您将获得一个表示比较两个对象的结果的值。这将是NSOrderedSameNSOrderedDescendingNSOrderedAscending之一。


我不清楚您的selfArraynewArray值是什么意思。您似乎正在比较selfArray中的值,但之后根据该比较更改newArray的顺序。它听起来并不像你在询问用于排序事物的算法,所以我只是把它留下来。

答案 1 :(得分:1)

一个类可以在定义后立即使用。因为它可以在里面使用。

NSArray可能在其实现中使用了NSMutableArray,但这很麻烦,因为NSArray是NSMutableArray的超类,如果超类依赖于知识子类,则认为它设计不好。

但...

实际上我们从不处理NSArrays,也没有处理NSMutableArrays,它们是class clusters,在实例化时创建了其他子类,如__NSArrayI(不可变)和__NSArrayM(可变)。如果他们都知道公共NSMutableArray接口,那就绝对没问题。

可能这个方法在数组上只是双循环(更可能是一些更好的排序算法,甚至是几个用于不同的内存情况),并在返回不可变副本之前填充NSMutableArray。


运行时复杂度为O( n 2 )的基本实现和O(1)的内存使用情况可能如下所示:

@interface NSArray (Comparator)
-(NSArray *)vs_sortedArrayUsingComparator:(NSComparisonResult(^)(id obj1, id obj2))comparator;
@end

@implementation NSArray (Comparator)

-(NSArray *)vs_sortedArrayUsingComparator:(NSComparisonResult(^)(id obj1, id obj2))comparator
{
    NSMutableArray *array = [self mutableCopy];
    if ([array count] > 1) {
        for (NSUInteger i = 0; i < [array count] - 1; ++i) {
            for (NSUInteger j  = i; j < [array count]; ++j) {
                if (comparator(array[i], array[j]) == NSOrderedDescending) {
                    [array exchangeObjectAtIndex:i withObjectAtIndex:j];
                }
            }
        }
    }
    return [array copy];
}
@end

用法:

NSArray *array = @[@4, @9, @2, @1, @7];

array = [array vs_sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) {
    return  [obj1 compare:obj2];
}];

结果

(
    1,
    2,
    4,
    7,
    9
)

运行时复杂度为O( n log n )的更快实现,但需要更多内存(平均值:O(log( n )) ))将是快速排序  其中对象和枢轴元素之间的比较由比较器块执行:

@interface NSArray (Comparator)
-(NSArray *)vs_sortedArrayUsingComparator:(NSComparisonResult(^)(id obj1, id obj2))comparator;
@end

@implementation NSArray (Comparator)
-(NSArray *) quicksortUsingComparator:(NSComparisonResult(^)(id obj1, id obj2))comparator
{
    NSArray *array = [self copy];

    if ([array count]<2) return [array copy];

    id pivot = [array randomElement];
    NSMutableArray *array2= [NSMutableArray array];

    array = [array arrayByPerformingBlock:^id  (id element) { return element;}
                      ifElementPassesTest:^BOOL(id element) { return comparator(element, pivot) == NSOrderedAscending;}
                         elsePerformBlock:^    (id element) { if (element!=pivot) [array2 addObject:element];}
            ];
    return [[[array quicksortUsingComparator:comparator]
                                    arrayByAddingObject:pivot]
                                        arrayByAddingObjectsFromArray:[array2 quicksortUsingComparator:comparator]];
}

-(NSArray *)vs_sortedArrayUsingComparator:(NSComparisonResult(^)(id obj1, id obj2))comparator
{
    return [self quicksortUsingComparator:comparator];
}
@end

正如在两个实现中仅向公众呈现vs_sortedArrayUsingComparator:一样,很容易想象在场景后面可能会在不同情况下使用不同的算法。 Quicksort是一个非常快的,但对于非常大的列表,它可能会产生堆栈溢出。在这种情况下,最好切换到另一种可能较慢但实现就地排序的算法。


可以在此处找到Quicksort示例的完整实现:​​http://vikingosegundo.github.io/2015/02/05/implement-comparator/

包括

- (NSArray *)arrayByPerformingBlock:(id   (^)(id element))performBlock 
                ifElementPassesTest:(BOOL (^)(id element))testBlock
                   elsePerformBlock:(void (^)(id element))elseBlock;

-(id)randomElement;

  

什么是类型(在代码中:类型?)i

id,转换为«指向任何对象的指针»。您可以将其缩写为“任何对象”,因为Objective-C中的所有对象只能通过指针访问。

相关问题