【问题标题】:Checking whether a mutable set contains an object with identical properties [duplicate]检查可变集是否包含具有相同属性的对象[重复]
【发布时间】:2013-04-23 06:12:38
【问题描述】:

我想做的是创建一个NSMutableSet,其目的是计算有多少对唯一数据。

基本上,我有两个可变数组; xCoordinatesyCoordinates,以及一个名为 XYPoint 的自定义对象。重合索引处的每个 X 坐标和 Y 坐标结合起来在笛卡尔平面上形成一个点。例如,在索引 2 处,xCoordinates 数组中可能有数字 4,而在 yCoordinates 数组中可能有数字 8,从而得出点 (4, 8)。

现在,问题的关键是,我想做的是检查有多少 unique 点。我打算使用NSMutableSet 来做这件事。即:

for (int i = 0; i < [xCoordinates count]; i++) {

        XYPoint *newXY = [[XYPoint alloc] init];
        newXY.xCoordinate = [xCoordinates objectAtIndex:i];
        newXY.yCoordinate = [yCoordinates objectAtIndex:i];

        if ([distinct containsObject:newXY] == NO) {

            [distinct addObject:newXY];

        }

    }

不幸的是,这不起作用。有没有办法说;

if (there isn't an object in the set with an identical X coordinate property and Y coordinate property){

    Add one to the set;

}

?

【问题讨论】:

标签: objective-c


【解决方案1】:

NSSet 在测试成员资格时使用isEqual
isEqual:hashNSObject protocol 的一部分。

如果你的 XYPoint 类是从 NSObject 派生的,它会继承默认的 isEqual: 基于指针相等的实现。它比较内存地址以测试 2 个对象是否相同。
由于您的比较标准是位置,因此如果您的 2 个对象的 x/y 坐标相同,您必须在 XYPoint 类中覆盖 isEqual: 并返回 YES

还可以查看Collections Programming Topics。 还有一篇关于equality and hashing by Mike Ash的很详细的帖子。

更新
正如 JeremyP 在 cmets 中指出的那样,在覆盖 isEqual: 时,您应该始终提供 hash 的实现。详细信息在上面的 Mike Ash 文章中进行了解释。
还有一个问题讨论坐标here on Stack Overflow的良好哈希函数。

【讨论】:

  • +1 获取详细说明和 Mike Ash 链接。
  • 这比将坐标转换为字符串要好得多。但是您还需要覆盖-hash,以便两个相等的对象具有相同的哈希值。
  • 好点 - 谢谢。我更新了我的答案。
【解决方案2】:

这是 Rakesh 提案的增强版。

它没有数字到字符串转换的微妙之处,而且它省略了多余的条件。

它使用通用的NSValue 点包装器而不是您的自定义类XYPoint

for (NSUInteger i = 0; i < [xCoordinates count]; ++i) {
    CGPoint p = { [xCoordinates[i] floatValue], [yCoordinates[i] floatValue] };
   [distinct addObject:[NSValue valueWithCGPoint:p]];
}

【讨论】:

  • 只是一个注释。 valueWithCGPoint: 仅在 iOS 中可用。可可中有类似的东西吗?
  • 顺便说一句,这不会检查唯一性。
  • @Rakesh OS X 有valueWithPoint:。这里描述了将 CGPoints 放入 NSValue 的通用方法:stackoverflow.com/a/2577651/104790
  • @Rakesh 我认为很明显distinctNSMutableSet(关注唯一性)。这就是我称条件冗余的原因。
  • 是的。但是当以这种方式创建 CGPoints 时,对象之间的相等性不满足,具有相同坐标的点被添加到 distinct 集合中。所以OP的问题仍然存在。
【解决方案3】:

扩展 weichsel's answer 这是这里最好的,类实现看起来像这样:

@interface XYCoordinate : NSObject
-(id) initWithX: (NSNumber*) newX andY: (NSNumber*) newY;
@property (readonly, copy) NSNumber* x;
@property (readonly, copy) NDNumber* y;
@end

@implementation XYCoordinate

@synthesize x = _x;
@synthesize y = _y;

-(id) initWithX: (NSNumber*) newX andY: (NSNumber*) newY
{
    self = [super init];
    if (self != nil)
    {
         [self setX: newX];
         [self setY: newY];
    }
    return self;
}

-(BOOL) isEqual: (id) somethingElse
{
    BOOL ret = NO;
    if ([somethingElse isKindOfClass: [XYCoordinate class]])
    {
        ret = [[self x] isEqual: [somethingElse x]] && [[self y] isEqual: [somethingElse y]]
    }
    return ret;
}

-(NSUInteger) hash
{
     return [[self x] hash] + [[self y] hash];  // Probably a rubbish hash function, but it will do
}
@end

【讨论】:

    【解决方案4】:

    在我的脑海中,也许一些产生独特结果的操作对于您的特定情况就足够了(尽管可能不是最有效的解决方案)。

    for (int i = 0; i < [xCoordinates count]; i++) {
    
        NSString *xStr = [[xCoordinates objectAtIndex:i] stringValue];
        NSString *yStr = [[yCoordinates objectAtIndex:i] stringValue];
        NSString *coordStr = [NSString stringWithFormat:@"%@ %@",xStr,yStr]; //edited
        if (![distinct containsObject:coordStr]) {
           [distinct addObject:coordStr];
        }
    }
    

    我猜应该是这样。您的解决方案每次都不起作用,因为创建了一个新对象并且不相等。但是对于像上面这样的 NSString ,情况并非如此。只是一个快速的解决方案。

    【讨论】:

    • 有一个隐藏的错误。提示:考虑点:1、11 和 11、1。
    • @NikolaiRuhe:是的。没想到。已更新(在 %@s 之间添加了一个空格)。
    猜你喜欢
    • 2023-03-26
    • 2018-03-08
    • 1970-01-01
    • 2017-10-23
    • 2012-02-02
    • 2013-12-26
    • 2014-05-08
    • 1970-01-01
    • 2017-10-09
    相关资源
    最近更新 更多