Check if String contains any String from array

后端 未结 3 721
别那么骄傲
别那么骄傲 2021-01-21 01:47

I know I can check if a string contains another string like this

NSString *string = @\"hello bla bla\";
if ([string rangeOfString:@\"bla\"].location == NSNotFoun         


        
相关标签:
3条回答
  • 2021-01-21 01:54

    There you go:

    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 contains exactly the two desired strings.

    A little bit more magic later you have your code without writing a loop :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;
    }]];
    
    0 讨论(0)
  • 2021-01-21 02:03

    You could use a NSCompoundPredicate

    NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
    

    Where your subPredicates must look like

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

    To get there from

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

    You could use a for loop, but as you are opposed to that, let's cheat:

    by using a category I each NSArray functional mapping, but instead of looping, I use enumerating

    @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
    

    Now I can create the subPredicates like

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

    and create the compound predicate like

    NSCompoundPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:subPredicates];
    

    and use it

    BOOL doesContain = [predicate evaluateWithObject:string];
    

    et voilà: No (obvious) looping, while there is one hidden in the enumeration and probably in the predicate as-well.


    Now with the changed question you basically ask for filtering. You can use the same predicate for that:

    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 now contains

    (
        I have one head,
        I have two feet
    )
    

    the complete code

    #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;
    }
    
    0 讨论(0)
  • 2021-01-21 02:06

    Besides my cheating the my other question, here an idea how really to avoid time costly looping: Use Set computation magic!

    • created a class 'Sentence', instantiate it with the strings to test
    • created a 'Word' class that takes a word to search for
    • overwrite both classes' isEqual: method to match for if a word is in the sentence (use sets there too!)
    • put those into an array.
    • from this array create a NS(*)Set object
    • put all word in a set
    • execute union on it.
    0 讨论(0)
提交回复
热议问题