【问题标题】:What is the most efficient way to sort an NSSet?对 NSSet 进行排序的最有效方法是什么?
【发布时间】:2010-11-07 04:47:16
【问题描述】:

根据集合中对象的属性对NSSet/NSMutableSet 中的对象进行排序的最有效方法是什么?现在我这样做的方式是遍历每个对象,将它们添加到NSMutableArray,然后使用NSSortDescriptor 对该数组进行排序。

【问题讨论】:

    标签: objective-c cocoa data-structures sorting nsset


    【解决方案1】:

    尝试使用

    [[mySet allObjects] sortedArrayUsingDescriptors:descriptors];
    

    编辑:对于 iOS ≥ 4.0 和 Mac OS X ≥ 10.6 可以直接使用

    [mySet sortedArrayUsingDescriptors:descriptors];
    

    【讨论】:

    • 这与提问者的建议没有太大区别,并且可能在速度上大致相同,因为 -allObjects 返回一个自动释放的 NSArray,而 -sortedArrayUsingDescriptors: 返回一个单独的 NSArray(两者都是不可变的)。分配两个数组的成本并不比枚举(中等大小)集合中的所有元素少多少,并且需要两倍的空间。
    • 请注意,sortedArrayUsingDescriptors: 是 10.6 唯一的方法。如果您的目标是 10.5 或之前,您可能想尝试@QuinnTaylor 的方法
    • NSSet 还有一个 sortedArrayUsingDescriptors 方法,所以你可以跳过对 allObjects 的调用,直接调用 [mySet sortedArrayUsingDescriptors:descriptors];
    • @DonnaLea 这似乎是最好的方法,但在提出问题时它并不存在。更新答案,谢谢。
    • 这可能很明显,但请注意, sortedArrayUsingDescriptors 需要一个描述符数组,而不仅仅是一个描述符。 [mySet sortedArrayUsingDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@“name”升序:YES]]];
    【解决方案2】:

    对一组对象进行排序的“最有效方式”会根据您的实际意思而有所不同。随意的假设(前面的答案所做的)是一组中的一次性对象。在这种情况下,我想说这几乎是 @cobbal 建议和你想出的东西之间的折腾——可能类似于以下内容:

    NSMutableArray* array = [NSMutableArray arrayWithCapacity:[set count]];
    for (id anObject in set)
        [array addObject:anObject];
    [array sortUsingDescriptors:descriptors];
    

    (我说这是一个折腾,因为@cobbal 的方法创建了两个自动释放的数组,因此内存占用加倍。这对于小对象集无关紧要,但从技术上讲,这两种方法都不是很有效。)

    然而,如果您不止一次地对集合中的元素进行排序(尤其是在常规情况下),这绝对不是一种有效的方法。你可以保留一个 NSMutableArray 并使其与 NSSet 保持同步,然后每次调用 -sortUsingDescriptors:,但即使数组已经排序,它仍然需要 N 次比较。

    Cocoa 本身并不能提供一种有效的方法来按排序顺序维护集合。 Java 有一个TreeSet 类,它在插入或删除对象时按排序顺序维护元素,但 Cocoa 没有。正是这个问题促使我开发了类似的东西供我自己使用。

    作为我继承和改进的数据结构框架的一部分,我创建了一个protocol and a few implementations for sorted sets。任何具体的子类都将按排序顺序维护一组不同的对象。仍然需要改进——最重要的是它基于 -compare: 的结果进行排序(集合中的每个对象都必须实现)并且还不接受 NSSortDescriptor。 (一种解决方法是实现 -compare:比较对象上感兴趣的属性。)

    一个可能的缺点是这些类(当前)不是 NS(Mutable)Set 的子类,所以如果你必须传递一个 NSSet,它就不会被排序。 (该协议确实有一个返回 NSSet 的 -set 方法,它当然是无序的。)我计划尽快纠正这个问题,就像我在框架中对 NSMutableDictionary 子类所做的那样。绝对欢迎反馈。 :-)

    【讨论】:

      【解决方案3】:

      对于 iOS ≥ 5.0 和 Mac OS X ≥ 10.7 可以直接使用NSOrderedSet

      【讨论】:

      • 这并没有解决问题,你有一个现有的 NSSet 并想要对其进行排序。
      • 更重要的 NSOrderedSet 不代表排序的 NSSet。
      【解决方案4】:

      NSSet 是无序对象的集合。查看苹果引用数组是有序集合。

      看 NSArray 有一个关于排序示例的讨论 http://developer.apple.com/documentation/Cocoa/Conceptual/Collections/Articles/sortingFilteringArrays ...

      链接示例:

      NSInteger alphabeticSort(id string1, id string2, void *reverse)
      {
          if (*(BOOL *)reverse == YES) {
              return [string2 localizedCaseInsensitiveCompare:string1];
          }
          return [string1 localizedCaseInsensitiveCompare:string2];
      }
      

      // assuming anArray is array of unsorted strings
      
      NSArray *sortedArray;
      
      // sort using a selector
      sortedArray =
          [anArray sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
      
      // sort using a function
      BOOL reverseSort = NO;
      sortedArray =
          [anArray sortedArrayUsingFunction:alphabeticSort context:&reverseSort];
      

      【讨论】:

      • 哇,那个特定的 Apple 示例代码非常糟糕。为什么他们使用 void*、NSInteger 和 int 而使用 BOOL 更简单?为什么它会返回 NSInteger 而不是 NSComparisonResult?我确信这是为了与以前的 API 决策兼容,但这太丑了!我建议使用选择器(方法)而不是函数来对 Cocoa 集合进行排序——它更简单、更优雅。
      • @QuinnTaylor 我刚刚检查过,果然,sortedArrayUsingFunction:context: 的文档说该函数需要两个 ids 和一个 void * 并返回一个 NSInteger。至少,样本是正确的。 (他们似乎也更新了它——现在不那么糟糕了。)
      【解决方案5】:

      您不能对 NSSet 进行排序,因为“sortedArrayUsingFunction:”将结果设置为 NSArray... 所有上面的提示都只适用于 Array :)

      NSArray *myArray = [mySet sortedArrayUsingDescriptors:descriptors];
      

      工作完美,不需要其他方式:)

      【讨论】:

        【解决方案6】:

        从 OS X 10.7 和 iOS 5.0 开始,就有了NSOrderedSet。您可以使用它来保持对象在集合中并保持它们的顺序。 NSMutableOrderedSet 有排序方法。 在某些情况下,这可能会提高性能,因为您不必创建像 NSArray 这样的单独对象来存储已排序的项目。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-05
          • 2011-04-22
          • 2015-09-16
          • 1970-01-01
          • 2010-11-05
          • 2016-10-19
          相关资源
          最近更新 更多