web-dev-qa-db-ja.com

配列に別の配列の同じオブジェクトが含まれているかどうかを確認する最も速い方法

目標は、2つの配列を比較し、それらに同じオブジェクトが含まれているかどうかを確認することです(可能な限り高速-配列に多くのオブジェクトがあります)。 isEqual:で配列をチェックすることはできません。並べ替え方法が異なるためです。

私はすでにここに投稿されたソリューションを試しました( https://stackoverflow.com/a/1138417 -Peter Hoseyによる投稿の最後のコードスニペットを参照してください)。しかし、これは異なる方法でソートされた配列では機能しません。

現在使用しているコードは次のとおりです。

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;
    for (id objectInArray1 in array1) {
        BOOL objectFoundInArray2 = NO;
        for (id objectInArray2 in array2) {
            if ([objectInArray1 isEqual:objectInArray2]) {
                objectFoundInArray2 = YES;
                break;
            }
        }
        if (!objectFoundInArray2) {
            bothArraysContainTheSameObjects = NO;
            break;
        }
    }

    return bothArraysContainTheSameObjects;
}

これは機能しますが、2つのネストされた高速列挙です。より高速な比較を行う方法はありますか?

24
FrankZp

コードごとに、同じ数の要素に厳密であり、最初の配列の各オブジェクトは2番目の配列に存在する必要があり、その逆も同様です。

最速の方法は、両方の配列を並べ替えて比較することです。

例:

NSArray *array1=@[@"a",@"b",@"c"];
NSArray *array2=@[@"c",@"b",@"a"];

array1=[array1 sortedArrayUsingSelector:@selector(compare:)];
array2=[array2 sortedArrayUsingSelector:@selector(compare:)];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both have same elements");
}
else{
    NSLog(@"both having different elements");
}
40
Anoop Vaidya

両方の配列をセットに変換して比較するのはどうですか。

NSSet *set1 = [NSSet setWithArray:arr1];
NSSet *set2 = [NSSet setWithArray:arr2];

を使用して2つを比較する

if([set1 isEqualToSet:set2]) {

}
12
Shashank

受け入れられた答えを機能させようとしましたが、それは私の状況に最適なものではありませんでした。

私は この回答 を見つけました。そして、すべてのクレジットはメソッドの@joel kravetsに送られます。

基本的に、コンパレータを使用してソートすると、オブジェクトを使用してより簡単にソートできます。したがって、上記のソリューションを使用しようとしたときに直面していた問題です。

NSArray * array1 = [NSArray arrayWithArray:users];
NSArray * array2 = [NSArray arrayWithArray:threadUsers];

id mySort = ^(BUser * user1, BUser * user2){
    return [user1.name compare:user2.name];
};

array1 = [array1 sortedArrayUsingComparator:mySort];
array2 = [array2 sortedArrayUsingComparator:mySort];

if ([array1 isEqualToArray:array2]) {
    NSLog(@"both are same");
}
else{
    NSLog(@"both are different");
}

以前は、上記のような他の回答を使用して、ループを通過するためにブレークを使用しようとしましたが、最終的にはおそらくその答えのためにこの回答が最も簡単に出てきましたそれらが同じか異なる場合。

私を正しい軌道に乗せてくれたAnoopと、効率を高める助けをしてくれたJoelに感謝します。

3
simon_smiley

配列全体を繰り返すのではなく、containsObject:メソッドを使用します。

NSArray *array;
array = [NSArray arrayWithObjects: @"Nicola", @"Margherita",                                       @"Luciano", @"Silvia", nil];
if ([array containsObject: @"Nicola"]) // YES
  {
    // Do something
  }

このような

+ (BOOL)arraysContainSameObjects:(NSArray *)array1 andOtherArray:(NSArray *)array2 {
    // quit if array count is different
    if ([array1 count] != [array2 count]) return NO;

    BOOL bothArraysContainTheSameObjects = YES;

    for (id objectInArray1 in array1) {

        if (![array2 containsObject:objectInArray1])
        {
            bothArraysContainTheSameObjects = NO;
            break;
        }

    }

    return bothArraysContainTheSameObjects;
}
3
NSArray *filtered = [someArray filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"someParamter == %@", paramValue]]];
if (filtered.count) {

}

主な利点は、カスタム、システム、NSDictionaryなど、あらゆる種類のオブジェクトに使用できることです。たとえば、UINavigationControllerのスタックにMySearchResultsVCとMyTopMenuItemsVCが含まれているかどうかを知る必要があります。

    NSArray *filtered = [self.navigationController.viewControllers filteredArrayUsingPredicate:
                                     [NSPredicate predicateWithFormat:@"class IN %@",
                                      [NSArray arrayWithObjects:
                                       [MySearchResultsVC class],
                                       [MyTopMenuItemsVC class],
                                       nil]]];
if (filtered) {
/* ok, now we can handle it! */
}
1
iiFreeman

このように、複雑さはO(N ^ 2)です。このアプローチに従えば、複雑さを低くすることはできません。一方、両方の配列を並べ替えて比較する場合は、O(N log(N))で実行できます。このように、それらをソートした後、他のN操作でisEqualToArray:を使用してそれを行います。

1
Ramy Al Zuhouri
[docTypes containsObject:@"Object"];

必要に応じて機能します。早くてもそれはブール値を返します。

1
Madhu

両方の配列に同じ重複が含まれているかどうかを確認する場合は、NSCountedSetを使用します。 NSSetに似ていますが、セット内の各オブジェクトには、追加された頻度を示すカウントもあります。そう

BOOL same = (array1.count == array2.count);
if (same && array.count > 0)
{
    NSCountedSet* set1 = [[NSCountedSet alloc] initWithArray:array1];
    NSCountedSet* set2 = [[NSCountedSet alloc] initWithArray:array2];
    same = ([set1 isEqual: set2]);
}

どのように実行しても、これには時間がかかるため、より迅速に処理できる特別なケースがあるかどうかを検討することができます。通常、これらの配列は同じか、ほぼ同じですか、それとも99%が異なり、99%のarray1のランダム要素がarray2にないのは本当ですか?配列は頻繁にソートされていますか?その場合、同じ位置に同じオブジェクトがあるかどうかを確認し、同じではないオブジェクトのみを考慮することができます。 1つの配列にオブジェクトa、b、c、d、eが含まれ、もう1つの配列にa、b、x、d、yが含まれる場合、配列[c、e]と[x、y]を比較するだけです。

1
gnasher729

私はそれが遅いことを知っていますが、私は自分がやったことを共有したいだけです。

NSString *stringArr1 = [NSString stringWithFormat:@"%@", array1];
NSString *stringArr2 = [NSString stringWithFormat:@"%@", array2];

if ([stringArr1 isEqual: stringArr2])
    NSLog(@"identical");
else
    NSLog(@"not");

これは比較するだけです"@ [@ 1、@ 2、@ 3、@ 4]" == "[@ 3、@ 2、@ 1、@ 4]" ..これは明らかにfalse ..

0
0yeoj