【问题标题】:How to turn an NSArray of strings into an array of unique strings, in the same order?如何以相同的顺序将字符串的 NSArray 转换为唯一字符串的数组?
【发布时间】:2011-05-11 17:21:45
【问题描述】:

如果你有一个 NSArray 字符串

{ @"ONE", @"ONE", @"ONE", "TWO", @"THREE", @"THREE" }

我怎么把它变成

{ @"ONE", @"TWO", @"THREE" }

..数组遵循与原始相同的顺序。我认为您可以将数组转换为 NSSet 以获取唯一项,但如果将其转换回数组,则不能保证获得相同的顺序..

【问题讨论】:

    标签: iphone objective-c ios nsarray nsset


    【解决方案1】:

    我最初的想法是你可以这样做:

    NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
    NSLog(@"%@", [a valueForKeyPath:@"@distinctUnionOfObjects.self"]);
    

    但这并不能维持秩序。因此,您必须手动完成:

    NSArray * a = [NSArray arrayWithObjects:@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE", nil];
    NSMutableArray * unique = [NSMutableArray array];
    NSMutableSet * processed = [NSMutableSet set];
    for (NSString * string in a) {
      if ([processed containsObject:string] == NO) {
        [unique addObject:string];
        [processed addObject:string];
      }
    }
    

    我使用NSMutableSet 来确定我之前是否已经遇到过这个条目(而不是[unique containsObject:string],因为一个集合的查找时间为 O(1),而一个数组的查找时间为 O(n)时间。如果您只处理少量对象,那么这无关紧要。但是,如果源数组非常大,那么使用集合来确定唯一性可能会增加一点速度。(但是,你应该使用 Instruments 来分析你的代码,看看是否有必要)

    【讨论】:

    • @distinctUnionOfObjects 弄乱了顺序真的不是最直观的事情(实现似乎只是做旧的 setWithArray:/allObjects),因为它需要并返回一个数组。
    • 感谢您的这篇文章。我发现它非常有用,但是,我还发现如果您只是尝试从第一个数组加载第二个数组而没有重复,那么您不需要 NSMutableSet。您可以只使用 for 循环和 if 语句来检查每个对象并在必要时添加它。很有用。谢谢
    【解决方案2】:

    你可以这样做:

    NSArray * uniqueArray = [[NSOrderedSet orderedSetWithArray:duplicatesArray] array];
    

    这样,您也可以保留订单!

    【讨论】:

    • 没错但应该是 NSArray * uniqueArray = [[NSOrderedSet orderedSetWithArray:duplicatesArray] allObjects]
    • @thewormsterror 如果它是 NSSet,您将是正确的,但答案使用没有 allObjects 属性的 NSOrderedSet,而是提供了数组属性。 developer.apple.com/documentation/foundation/nsorderedset/…
    【解决方案3】:

    我认为你可以这样做

    NSArray * uniqueArray = [[Yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
    

    希望对你有帮助

    【讨论】:

    • +1:这就是我想要的。但是,这并不能满足提问者的要求,因为这不会保持原始数组的顺序......(1)[Yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"] 不尊重顺序,(2)sortedArrayUsingSelector:@selector(caseInsensitiveCompare:) 显然对数组进行排序。 .. 如果您正在寻找一种“过滤掉重复项并按字母顺序对最终数组进行排序”的方法,那么这就是您的最佳选择。 :D
    【解决方案4】:

    嗯..你可以只使用一个循环吗?

    NSMutableArray *newarray = [[NSMutableArray alloc] init];
    NSString *laststring = nil;
    for (NSString *currentstring in oldarray) 
    {
       if (![currentstring isEqualtoString:laststring]) [newarray addObject:currentstring];
       laststring = currentstring
    }
    

    【讨论】:

    • 谢谢..这取决于原始数组是否真的以这种方式排序......如果像 ("one", "one", "two", "one", "three") 是可能作为原始数组它不起作用。
    • 嗯,但这只有在相同的元素在数组中总是相邻的情况下才有效,对吧?在这种情况下,这似乎是真的,但谁知道......
    【解决方案5】:

    这是一个很好的类别,它定义了一个类似于@distinctUnionOfObjectscustom operator,除了它只适用于字符串并且它将保持它们的原始 顺序。注意:它不会为您对字符串进行排序。它只保留重复字符串的第一个实例。

    用法:

    #import "NSArray+orderedDistinctUnionOfStrings.h"
    ...
    // if you feed it an array that has already been ordered, it will work as expected
    NSArray *myArray = @[@"ONE", @"ONE", @"ONE", @"TWO", @"THREE", @"THREE"];
    NSArray *myUniqueArray = [myArray valueForKeyPath:@"@orderedDistinctUnionOfStrings.self"];
    

    输出:

    myUniqueArray = ( "ONE", "TWO", "THREE" )
    

    .h 文件:

    #import <Foundation/Foundation.h>
    
    @interface NSArray (orderedDistinctUnionOfStrings)
    
    @end
    

    .m 文件:

    #import "NSArray+orderedDistinctUnionOfObjects.h"
    
    @implementation NSArray (orderedDistinctUnionOfObjects)
    
    - (id) _orderedDistinctUnionOfStringsForKeyPath:(NSString*)keyPath {
        NSMutableIndexSet *removeIndexes = [NSMutableIndexSet indexSet];
    
        for (NSUInteger i = 0, n = self.count; i < n; ++i) {
            if ([removeIndexes containsIndex:i]) {
                continue;
            }
            NSString *str1 = [[self objectAtIndex:i] valueForKeyPath:keyPath];
    
            for (NSUInteger j = i+1; j < n; ++j) {
                if ([removeIndexes containsIndex:j]) {
                    continue;
                }
                id obj = [self objectAtIndex:j];
                NSString *str2 = [obj valueForKeyPath:keyPath];
                if ([str1 isEqualToString:str2]) {
                    [removeIndexes addIndex:j];
                }
            }
        }
    
        NSMutableArray *myMutableCopy = [self mutableCopy];
        [myMutableCopy removeObjectsAtIndexes:removeIndexes];
    
        return [[NSArray arrayWithArray:myMutableCopy] valueForKeyPath:[NSString stringWithFormat:@"@unionOfObjects.%@", keyPath]];
    }
    
    @end
    

    这是一本关于如何生成自己的运算符的优秀读物,并(稍微)揭开了它的工作原理:http://bou.io/KVCCustomOperators.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-13
      • 2020-01-13
      • 1970-01-01
      相关资源
      最近更新 更多