25

目標は、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 つのネストされた高速列挙です。比較を高速化する方法はありますか?

4

10 に答える 10

43

コードによると、同じ数の要素に厳密であり、最初の配列の各オブジェクトは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");
}
于 2013-02-18T11:45:57.577 に答える
13

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

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

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

if([set1 isEqualToSet:set2]) {

}
于 2013-02-18T11:36:31.537 に答える
3

配列全体を反復する代わりに、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;
}
于 2013-02-18T11:45:11.200 に答える
3

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

私はこの答えを見つけました。すべての功績は、メソッドの@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に感謝します

于 2014-10-30T04:51:47.203 に答える
2

両方の配列に同じ重複が含まれているかどうかを確認したい場合は、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% の確率で配列 1 のランダムな要素が配列 2 にないということですか? 配列はよくソートされていますか? その場合、同じ位置に同じオブジェクトがあるかどうかを確認し、同じでないオブジェクトのみを考慮することができます。1 つの配列にオブジェクト a、b、c、d、e が含まれ、もう 1 つの配列に a、b、x、d、y が含まれる場合、配列 [c, e] と [x, y] のみを比較する必要があります。

于 2014-03-12T17:11:48.730 に答える
1

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

于 2013-02-18T11:36:28.963 に答える
1
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! */
}
于 2013-02-18T16:36:04.630 に答える
0

遅いことはわかっていますが、私がしたことを共有したいだけです..

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]"を比較するようなものです..これは明らかに誤りです..

于 2015-05-15T11:01:37.207 に答える
-5

私はこれがうまくいくと思います:

[array1 isEqualToArray:array2];

ブール値を返します。

于 2013-02-18T11:33:26.940 に答える