如果我使用比较对对象进行排序,如果其中一个对象为零,我如何告诉它不排序?

Posted

技术标签:

【中文标题】如果我使用比较对对象进行排序,如果其中一个对象为零,我如何告诉它不排序?【英文标题】:If I'm sorting objects using compare, how do I tell it to not sort if one of the objects is nil? 【发布时间】:2013-09-01 20:52:23 【问题描述】:

假设我有以下代码块:

[allKeys sortUsingComparator:^NSComparisonResult(id obj1, id obj2) 
    NSDictionary *firstArticle = [articles objectForKey:(NSString *)obj1];
    NSNumber *firstSortID = [firstArticle objectForKey:@"sort_id"];

    NSDictionary *secondArticle = [articles objectForKey:(NSString *)obj2];
    NSNumber *secondSortID = [secondArticle objectForKey:@"sort_id"];

    if (firstSortID == nil || secondSortID == nil) 
        return nil;
    
    else 
        return [secondSortID compare:firstSortID];
    
];

我收到警告:

指向整数转换的不兼容指针从 a 返回“void *” 结果类型为“NSComparisonResult”(又名“枚举”)的函数 NSComparisonResult')

但基本上,如果其中一个为 nil,它会崩溃,因为比较没有意义。我怎么告诉它,如果它是 nil,不要打扰,停下来。

【问题讨论】:

警告:您返回 nil 而不是 NSComparisonResult ... 是什么保存了已排序的对象?通常的 NS 数据结构都没有存储 nil。 【参考方案1】:

您必须决定如何对 nil 值进行排序。他们很可能应该排在列表的末尾。你想要这样的东西:

if (firstSortID) 
    if (secondSortID) 
        // Both set, compare
        NSComparisonResult result = [firstSortID compare:secondSortID];
        if (result == NSOrderedSame) 
            // optionally do another comparison on a secondary value
            // result = ...
        
        return result;
     else 
        // Have 1st but not 2nd
        return NSOrderedAscending;
    
 else 
    if (secondSortID) 
       // Have 2nd but not 1st
       return NSOrderedDescending;
     else 
       // Both nil, treat as the same
       // Another option here is to look at another value in the dictionary to be used as a secondary sort
       return NSOrderedSame;
    

【讨论】:

最简单的解决方案,但是带有 nil 属性的对象的顺序会不稳定。 当两个值都是nil时,如果使用代码注释中所述的辅助值,则解决此问题。 无论对象状态如何,我都无法思考这是否会产生有保证的稳定排序。 IE。仅在 nil,nil 上下文中切换排序键有效吗? 其实,如果两个值都不是nil并且compare:的结果返回NSOrderedSame,你也需要二次(甚至更高)排序。我会用这个细节更新我的答案。【参考方案2】:

您不能使用sortUsingComparator: 提前终止排序。因此,您必须对 nil 值进行排序 - 只需确定 nil 应该是最小值还是最大值,然后根据需要返回 NSOrderedDescendingNSOrderedAscendingNSOrderedSame

如果您需要知道您是否点击了nil,请在您的块中设置一个标志,然后您可以对其进行测试。该标志需要使用 __block 限定符声明,以便可以在您的块中进行修改,例如:

__block BOOL nilFound = NO;
[allKeys sortUsingComparator:^NSComparisonResult(id obj1, id obj2)

   NSDictionary *firstArticle = [articles objectForKey:(NSString *)obj1];
   NSNumber *firstSortID = [firstArticle objectForKey:@"sort_id"];

   NSDictionary *secondArticle = [articles objectForKey:(NSString *)obj2];
   NSNumber *secondSortID = [secondArticle objectForKey:@"sort_id"];

   // set flag - could alternatively be set during comparison logic below
   if (firstSortID == nil || secondSortID == nil)
      nilFound = YES;

   // actual comparison, allowing for nil values
   ...
];

// was a nil found?
if (nilFound) ...

附录

其他人提出了稳定排序的问题,您应该能够通过使用原始键来解决这个问题,例如:

if (firstSortID == nil)

   if (secondSortID == nil)
   
      // both nil - use original keys as secondary sort, obj1 & obj2 are strings
      return [obj1 compare:obj2];
   
   else
      return NSSortAscending;

else
   return secondSortID == nil ? NSSortDescending : [secondSortID compare:firstSortID];

(您可以切换 NSSortAscendingNSSortDescending 以将 nil 值分组在另一端。)

【讨论】:

您不需要让== nil 检查类型是否可以是 id。 if (!firstSortID || !secondSortID) 已经足够好了。 @OliverAtkinson - 任何对象引用(或 C 指针 et al.)都可以按照您的建议进行测试。选择很大程度上取决于风格。

以上是关于如果我使用比较对对象进行排序,如果其中一个对象为零,我如何告诉它不排序?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用以下代码根据实例变量对对象数组进行升序排序

js使用Array.prototype.sort()对数组对象排序的方法

按对象属性之一的值对对象列表进行排序,其中只有一个值是感兴趣的

如果附件为零,如何在报表上隐藏附件(图像)对象?

JQuery使用日期对对象数组进行排序[重复]

java 如何对对象进行排序