【问题标题】:compare two arrays and get the common items比较两个数组并得到共同项
【发布时间】:2011-11-06 23:00:00
【问题描述】:

我有两个数组,但它们有不同的长度。我想比较这两个数组并将常用项放入一个新数组。同时不应该有重复项是第三个数组。 我真的搞砸了,请帮帮我。 非常感谢。 . .

【问题讨论】:

    标签: iphone objective-c ios iphone-sdk-3.0


    【解决方案1】:

    这样的?

    NSMutableSet* set1 = [NSMutableSet setWithArray:array1];
    NSMutableSet* set2 = [NSMutableSet setWithArray:array2];
    [set1 intersectSet:set2]; //this will give you only the objects that are in both sets
    
    NSArray* result = [set1 allObjects];
    

    这样做的好处是不查找数组中的对象,而循环遍历另一个数组,该数组具有 N^2 复杂性,如果数组很大,可能需要一段时间。

    编辑:set2 不必是可变的,不妨只使用

    NSSet* set2 = [NSSet setWithArray:array2];
    

    【讨论】:

    • FWIW,当然intersectSet: 将不得不做类似的事情(检查项目并比较),但它对其进行了优化,因此最终可能会更快地复制所有这些项目都在集合周围,往返集合。 OTOH,Akshay 提出的简单循环,可能会更快,因为它不会复制太多。必须针对需要的情况分析这两种方法。
    • @Rudy Velthuis 我认为 intersetSet: 在最坏的情况下具有相同的复杂性,但通常表现更好。并且 setWithArray 将保留,而不是复制对象。但可以肯定的是,在某些情况下,像 Akshay 建议的那样通过数组进行直接迭代可能会更好。
    • @Rudy Velthuis:任何健全的集合实现都将针对快速成员资格测试进行优化,并且可以比线性测试更好地扩展——在最坏的情况下,集合中的成员资格测试应该是对数的。此外,集合和数组都不会复制它们的成员,所以那里不应该有太大的放缓。
    • @Chuck:正如我所说,复制至少意味着必须保留每个项目。数组和结果都会发生这种情况。我知道集合是经过优化的,但它们也需要时间来进行比较。使用数组初始化集合意味着也必须拒绝重复项(即使集合可以非常快地做到这一点)。事实是,这一切都需要时间,无论一组多么优化。而且,套装中的物品最终也必须发布。 当然可以猜测哪个更快,但只有正确的分析才能判断这是不是真的
    • 所以我做了一些简单的“手动”分析(我会发布代码,如果有人告诉我在哪里可以做到这一点),使用集合的解决方案大约是 10 倍一个使用containsObject: 的简单循环。我的方法大约需要。是使用集合的 1.5 倍。
    【解决方案2】:

    第三种方法(除了使用集合或使用包含检查每个项目的简单循环之外)是对两个数组进行排序,然后使用两个索引:

    // approach using sets:
    
    NSArray *arrayUsingSets(NSMutableArray *arr1, NSMutableArray *arr2)
    {
        NSMutableSet *set1 = [NSMutableSet setWithArray: arr1];
        NSSet *set2 = [NSSet setWithArray: arr2];
        [set1 intersectSet: set2];
        return [set1 allObjects];
    }
    
    // my approach:
    
    NSArray *arrayUsingComp(NSMutableArray *arr1, NSMutableArray *arr2)
    {
        NSMutableArray *results = [NSMutableArray arrayWithCapacity: arr1.count + arr2.count];
    
        // Assumes input arrays are sorted. If not, uncomment following two lines.
    //    [arr1 sortUsingSelector: @selector(compare:)];
    //    [arr2 sortUsingSelector: @selector(compare:)];
    
        int i = 0;
        int j = 0;
        while ((i < arr1.count) && (j < arr2.count))
        {
            switch ([[arr1 objectAtIndex: i] compare: [arr2 objectAtIndex: j]])
            {
                case NSOrderedSame:
                    [results addObject: [arr1 objectAtIndex: i]];
                    i++, j++;
                    break;
                case NSOrderedAscending:
                    i++;
                    break;
                case NSOrderedDescending:
                    j++;
                    break;
             }
        }
    
        // NOTE: results are sorted too.
        // NOTE 2: loop must go "backward".
        for (NSInteger k = results.count - 1; k > 0; k--) 
            if ([[results objectAtIndex: k] isEqual: [results objectAtIndex: k-1]])
                [results removeObjectAtIndex: k];
    
        return results;    
    }
    

    我做了一些简单的分析,如果我对传入的数组制作可变副本并对其进行排序,它的执行速度比使用集合的方法慢 1.5 倍。我上面的方法似乎比使用集合的方法执行速度快 1.5 倍。如果保证数组已经排序,我的方法将执行得更好(几乎是使用集合的版本的 4 倍),因为不需要排序。

    更新:

    这并没有消除重复,所以我在例程的末尾添加了循环。现在它只比使用集合的方法快 3 倍,但仍然...

    【讨论】:

    • 很有趣,但它不能确保 array3 不会有重复项 - 比如说,如果 array1 和 array2 都有 3 个元素:1 1 1(用于简单说明的整数),那么 array3 最终将有同样的 3 个元素。
    • 嗯...是的,可能。正在努力。
    • @SVD: 致力于它。如果对原始项目进行排序,现在它的速度只有 3 倍。如果不是,它只比使用集合的方法快一点。
    • 我一个有 93 个,另一个有 81 个,所有 arc4random() % 300,加上一些额外的重复项。我在相同的阵列上进行了 10000 次计时测试。我可以尝试使用更大的数组...我只是分别尝试了 1793 和 1681 NSNumbers,arc4random() % 3000 并得到了类似的结果。
    • 我刚刚分别尝试了 100000 和 103245,但我仍然看到我的解决方案的速度是原来的 4 倍(如果数组已经排序)。如果数组必须按我的例程排序,它仍然快 20% 左右。请注意,我设置了数组,因此如果 (arc4random() % 4 == 1),我将再次将最后一个对象添加到数组中。所以这是相当比例的重复。
    【解决方案3】:

    遍历array1并在array2中搜索它。如果找到,则将其添加到 array3,如果它还没有。

    for (MyObject* obj in array1)
    { 
         if([array2 containsObject:obj] && ![array3 containsObject:obj])
            [array3 addObject:obj];
    }
    

    如果您的 array1 没有重复项,则不需要第二次检查。

    【讨论】:

    • 或者使用 NSMutableSet 容器
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-04
    • 1970-01-01
    • 2015-05-10
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    相关资源
    最近更新 更多