2016-07-30 4 views
0

Objective-CクラスがFactorHelperと定義されています。それはNSMutableArrayNSNumbersの要因と呼ばれる特性を持っています。 2つのFactorHelperオブジェクトのfactorプロパティが同じ番号を持つ場合(たとえ数値が異なる順序であっても)、trueを返すこのクラスのカスタムisEqual:メソッドがあります。* [NSMutableSet addObject:X] *既に[セット]内にあるオブジェクトYに対して* [Y isEqual:X] *がTRUEを返す場合でもオブジェクトXを追加します

私は2つのFactorHelperオブジェクト10,2,5と10,5,2有するものとその他を作成することにより、テストしようとしました。次に、NSMutableSetを作成し、firstObjectを追加してから2番目のオブジェクトを追加しました。 2番目のオブジェクトが追加されないことを期待していましたが、追加されています。コードをステップ実行すると、isEqualがaddObjectによって呼び出され、TRUEが返されています。私は間違って何をしていますか? [NSMutableSet alloc] init][NSMutableSet new]を変更

UPDATE

は期待通りに物事が動作します。

また、すべてのTRUEを変更するとFALSEはisEqualがYESになり、NOは正しく動作します([NSMutableSet new]として保持しても)。

私は何が起こっているのか分かりません。誰かが光を放つことができますか?

クラス定義

@interface FactorHelper: NSObject 
@property NSMutableArray <NSNumber *> *factors; 
-(BOOL) isEqual:(FactorHelper *)other; 
-(instancetype) initWithFactors:(NSMutableArray *)factors; 
-(NSString *) description; 
@end 

@implementation FactorHelper 

- (instancetype) initWithFactors:(NSMutableArray *)factors 
{ 
    self = [super init]; 

    if (self) { 
     _factors = factors; 
    } 

    return self; 
} 

-(BOOL) isEqual:(FactorHelper *)other 
{ 
    if ([self.factors count] != [other.factors count]) 
    { 
     return FALSE; 

    } 
    else 
    { 
     NSMutableDictionary <NSNumber *, NSNumber *> *myHashTable = [[NSMutableDictionary alloc] init]; 
     for (NSNumber *nextNumber in self.factors) { 
      if(myHashTable[nextNumber] == nil) 
      { 
       myHashTable[nextNumber] = @(1); 
      } 
      else 
      { 
       myHashTable[nextNumber] = @([myHashTable[nextNumber] integerValue]+1); 
      } 
     } 

     for (NSNumber *nextNumber in other.factors) 
     { 
      if(myHashTable[nextNumber] == nil) 
      { 
       return FALSE; 
      } 
      else 
      { 
       myHashTable[nextNumber] = @([myHashTable[nextNumber] integerValue] - 1); 

       if ([myHashTable[nextNumber] integerValue] == 0) { 
        [myHashTable removeObjectForKey:nextNumber]; 
       } 
      } 
     } 

     if ([[myHashTable allKeys] count] == 0) 
     { 
      return TRUE; 
     } 
     else 
     { 
      return FALSE; 
     } 

    } 
} 
@end 

ユニットテストコード

NSMutableSet *testSet = [NSMutableSet new]; 
FactorHelper *fact1 = [[FactorHelper alloc] initWithFactors:[@[@(10),@(5),@(2)] mutableCopy]]; 
FactorHelper *fact2 = [[FactorHelper alloc] initWithFactors:[@[@(10),@(2),@(5)] mutableCopy]]; 
[testSet addObject:fact1]; 
[testSet addObject:fact2]; 
NSLog(@"Are factors 1 and 2 the same: %d",[fact1 isEqual:fact2]); 
+0

あなたのコードでは、NSMutableSetを使用していますか? – Willeke

+0

testSetはNSMutableSetです。上記のメインコードに追加されました。このコードは、OS Xのコマンドラインツールのメインメソッドの中にあります。下の私の答えを見てください。すべてのTRUE/FALSEをYES/NOに変更すると、問題が修正されました。 –

答えて

2

NSMutableSetは、ハッシュ値ベースのセットです。 isEqual:と一致するその要素タイプに対して、hashメソッドをオーバーライドする必要があります。あなたのケースでは

、このような何か:私はが、私はそれが追加されたことがわかり、これはNSMutableSetであなたのFactorHelper作業を行う場合、あなたがチェックかどうかはわかりません

- (NSUInteger)hash { 
    NSCountedSet *factorCounts = [[NSCountedSet alloc] initWithArray:self.factors]; 
    return [@"FactorHelper" hash] + [factorCounts hash]; 
} 

ところで、isEqual:は、NSCountedSetを使用して少し短く実装できます。

-(BOOL) isEqual:(FactorHelper *)other { 
    NSCountedSet *myFactorCounts = [[NSCountedSet alloc] initWithArray:self.factors]; 
    NSCountedSet *otherFactorCounts = [[NSCountedSet alloc] initWithArray:other.factors]; 
    return [myFactorCounts isEqual:otherFactorCounts]; 
} 

これは上記hashと明確一貫性を示しています。

+0

ありがとう@OOPer。 1つの質問:すべてのAppleコレクションクラスに "ハッシュ"が組み込まれていますか?たとえば、私がカスタムクラスCLassXを持っている場合、そのプロパティには 'NSArray * array'と' NSInteger vale'という2つのプロパティがあります。 CLassXの2つのオブジェクトは、配列と値の要素を持つ限り同じであると言いたいと思います。ハッシュを[self.array hash] + [self.value hash]に設定するだけですか? –

+0

@SmartHome、私が知る限り、すべてのコレクション型は 'isEqual:'メソッドと一致するハッシュ値を返します。つまり、 '[col1 isEqual:col2]'がTRUEを返すと、 '[col1 hash] == [col2 hash]'は常にTRUEになります。 ( 'NSArray * array'、' NSInteger value')に対して等価で定義された 'hash'を実装するために、' [self.array hash] +(NSUInteger )self.value'が動作します。 (より良い実装があるかもしれませんが、これはそれほど悪くはありません)。 – OOPer

+0

@SmartHome、多分私は "一貫性は効率的ではありません"ということに注意する必要があります。 '' NSDictionary'や 'NSSet'のようなハッシュベースのコレクションでより良いパフォーマンスを得るためには' '[col1 hash] == [col2 hash]'ではなく '[col1 isEqual:col2]' "の可能性を最小化する必要があります。 Appleのフレームワークにおける 'hash'のデフォルトの実装は、その目的のために最適化されたものから遠く離れているかもしれません。 – OOPer

1

あなたのコードは、それが時々登場した場合でも、働いたことがないました。

問題は、isEqualのカスタム実装が、Setでクラスを動作させるための唯一の要件ではないということです。考えてみてください:ですか? ハッシュテーブルです。したがって、hashの一致するカスタム実装を提供する必要があります。これは実行していません。

ハッシュ可能性の要件は、2つのオブジェクトが等しい場合、2つのオブジェクトのハッシュ値が同じでなければならないことです。

関連する問題