【问题标题】:Check if String contains any String from array检查字符串是否包含数组中的任何字符串
【发布时间】:2015-09-08 08:09:46
【问题描述】:

我知道我可以检查一个字符串是否包含另一个这样的字符串

NSString *string = @"hello bla bla";
if ([string rangeOfString:@"bla"].location == NSNotFound) {
  NSLog(@"string does not contain bla");
} else {
  NSLog(@"string contains bla!");
}

但是如果我有一个NSArray *arary = @[@"one",@"two", @"three", @"four"] 并且我想检查一个字符串是否包含其中一个而没有循环或有一堆或(||)。所以会是这样的

if (array contains one or two or three or four) {
//do something
}

但是,如果我有一个更长的数组,这会变得乏味,所以还有其他方法,而不仅仅是循环吗?

编辑

我想检查 myArray 在 valuesArray 中是否有这些值

valuesArray =@[@"one",@"two", @"three", @"four"];
myArray = [@"I have one head", @"I have two feet", @"I have five fingers"]

输出

outputArray = @[@"I have one head", @"I have two feet"]

【问题讨论】:

  • 您有什么特别的理由不想循环播放吗?
  • 这将需要一个循环,并且您将找不到更高效的解决方案,因为您基本上必须检查数组中的每个元素
  • 没关系。您必须遍历要测试的字符串,并且每次比较都是比较字符串的循环。您可以将其抽象出来,但是无论您调用什么函数或使用正则表达式,或者任何仍将执行循环的函数。您是否对此进行了测量并确保这实际上是您的应用程序的性能问题? N 有多大?
  • 即使你在不编写循环的情况下找到了解决方案,你也可以确定该方法在内部循环遍历数组——否则你将如何检查每个值? “2 个循环”和“针对数组运行”是什么意思?
  • 如果可能的话,为什么不使用或缓存你的数组到一个 NSDictionary 中呢?您可以检查是否存在键/值对,这将是一个恒定时间操作。您检查的值越多,这将变得越重要。

标签: ios objective-c arrays loops nsstring


【解决方案1】:

除了我在另一个问题上作弊之外,这里有一个想法如何真正避免耗时的循环:使用 Set 计算魔法!

  • 创建了一个“句子”类,用要测试的字符串对其进行实例化
  • 创建了一个“Word”类,用于搜索一个词
  • 覆盖两个类的isEqual: 方法以匹配句子中是否有单词(也使用集合!)
  • 将它们放入一个数组中。
  • 从此数组中创建一个NS(*)Set 对象
  • 将所有单词放在一个集合中
  • 对其执行联合。

【讨论】:

    【解决方案2】:

    你去吧:

    NSArray* arrRet = [myArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  __nonnull evaluatedObject, NSDictionary<NSString *,id> * __nullable bindings) {
        for(NSString* val in valuesArray) {
            if ([evaluatedObject rangeOfString:val].location != NSNotFound)
                return true;
        }
        return false;
    }]];
    

    arrRet 正好包含两个所需的字符串。

    稍后你的代码会更神奇,而无需编写循环:P

    NSArray* arrRet = [myArray filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id  evaluatedObject, NSDictionary<NSString *,id> * bindings) {
        BOOL __block match = false;
        [valuesArray enumerateObjectsUsingBlock:^(id  __nonnull obj, NSUInteger idx, BOOL * __nonnull stop) {
            *stop = match = [evaluatedObject rangeOfString:obj].location != NSNotFound;
        }];
        return match;
    }]];
    

    【讨论】:

    • 嗯,我认为我的映射是更好的作弊,因为它还隐藏了枚举。
    • @vikingosegundo 您知道使用谓词是否可以提高性能 - 只是出于好奇?
    • 我对谓词性能了解不多,但老实说:无论如何,它对你的神经元来说仍然太快了。如果您真的想获得性能,请参阅我刚刚发布的另一个答案:使用集合算术。
    • @vikingosegundo 嗯,我认为这两个版本对于他的用例来说都有些矫枉过正,至少在设置算术上是这样。关于性能,我指的是扩大规模 - 如果他为 100 个子字符串测试 1000 个字符串等会发生什么。懒得尝试它:P 但谓词答案实际上看起来很有趣 +1 :)
    • 只是发布到 Stackoverflow 以摆脱几个(数百个)字符串的 for 循环已经过大了!问题和答案是过早优化的罪魁祸首。
    【解决方案3】:

    你可以使用 NSCompoundPredicate

    NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
    

    你的子谓词必须是这样的

    (
        SELF CONTAINS[c] "one",
        SELF CONTAINS[c] "two",
        SELF CONTAINS[c] "three",
        SELF CONTAINS[c] "four"
    )
    

    从那里去

    NSArray *array = @[@"one", @"two", @"three", @"four"]
    

    您可以使用 for 循环,但由于您反对,让我们作弊吧:

    通过对每个 NSArray 函数使用一个类别 I 进行映射,但不是循环,而是使用枚举

    @interface NSArray (Map)
    -(NSArray *) vs_map:(id(^)(id obj))mapper;
    @end
    
    @implementation NSArray (Map)
    
    -(NSArray *)vs_map:(id (^)(id))mapper
    {
        NSMutableArray *mArray = [@[] mutableCopy];
        [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    
            id mapped = mapper(obj);
            [mArray addObject:mapped];
        }];
    
        return [mArray copy];
    }
    
    @end
    

    现在我可以像这样创建子谓词了

    NSArray *subPredicates = [arary vs_map:^id(NSString *obj) {
            return [NSPredicate predicateWithFormat:@"SELF contains[c] %@", obj];
    }];
    

    并创建复合谓词如

    NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
    

    并使用它

    BOOL doesContain = [predicate evaluateWithObject:string];
    

    etvoilà:没有(明显的)循环,而在枚举中隐藏了一个,也可能在谓词中。


    现在有了更改的问题,您基本上要求过滤。您可以为此使用相同的谓词:

    NSArray *testarray = @[@"I have one head", @"I have two feet", @"I have five fingers"];
    NSArray *arary = @[@"one",@"two", @"three", @"four"];
    
    NSArray *subPredicates = [arary vs_map:^id(NSString *obj) {
        return [NSPredicate predicateWithFormat:@"SELF contains[c] %@", obj];
    }];
    
    NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
    NSArray *results = [testarray filteredArrayUsingPredicate:predicate];
    

    results 现在包含

    (
        I have one head,
        I have two feet
    )
    

    完整代码

    #import <Foundation/Foundation.h>
    
    @interface NSArray (Map)
    -(NSArray *) vs_map:(id(^)(id obj))mapper;
    @end
    
    @implementation NSArray (Map)
    
    -(NSArray *)vs_map:(id (^)(id))mapper
    {
        NSMutableArray *mArray = [@[] mutableCopy];
        [self enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    
            id mapped = mapper(obj);
            [mArray addObject:mapped];
        }];
    
        return [mArray copy];
    }
    
    @end
    
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
    
    
            NSArray *testarray = @[@"I have one head", @"I have two feet", @"I have five fingers"];
            NSArray *arary = @[@"one",@"two", @"three", @"four"];
    
            NSArray *subPredicates = [arary vs_map:^id(NSString *obj) {
                return [NSPredicate predicateWithFormat:@"SELF contains[c] %@", obj];
            }];
    
            NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
            NSArray *results = [testarray filteredArrayUsingPredicate:predicate];
    
        }
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-01
      • 2012-04-30
      • 2021-12-14
      • 1970-01-01
      • 2011-12-23
      • 2015-02-28
      • 2021-06-10
      • 2013-09-27
      相关资源
      最近更新 更多