NSArray Equivalent of Map

后端 未结 11 1770
萌比男神i
萌比男神i 2020-11-28 05:06

Given an NSArray of NSDictionary objects (containing similar objects and keys) is it possible to write perform a map to an array of specified key?

相关标签:
11条回答
  • 2020-11-28 05:31

    For Objective-C, I would add the Higher-Order-Functions to this list of answers: https://github.com/fanpyi/Higher-Order-Functions;

    There is a JSON array studentJSONList like this:

    [
        {"number":"100366","name":"Alice","age":14,"score":80,"gender":"female"},
        {"number":"100368","name":"Scarlett","age":15,"score":90,"gender":"female"},
        {"number":"100370","name":"Morgan","age":16,"score":69.5,"gender":"male"},
        {"number":"100359","name":"Taylor","age":14,"score":86,"gender":"female"},
        {"number":"100381","name":"John","age":17,"score":72,"gender":"male"}
    ]
    //studentJSONList map to NSArray<Student *>
    NSArray *students = [studentJSONList map:^id(id obj) {
    return [[Student alloc]initWithDictionary:obj];
    }];
    
    // use reduce to get average score
    NSNumber *sum = [students reduce:@0 combine:^id(id accumulator, id item) {
    Student *std = (Student *)item;
    return @([accumulator floatValue] + std.score);
    }];
    float averageScore = sum.floatValue/students.count;
    
    // use filter to find all student of score greater than 70
    NSArray *greaterthan = [students filter:^BOOL(id obj) {
    Student *std = (Student *)obj;
    return std.score > 70;
    }];
    
    //use contains check students whether contain the student named 'Alice'
    BOOL contains = [students contains:^BOOL(id obj) {
    Student *std = (Student *)obj;
    return [std.name isEqual:@"Alice"];
    }];
    
    0 讨论(0)
  • 2020-11-28 05:32

    For Objective-C, I would add the ObjectiveSugar library to this list of answers: https://github.com/supermarin/ObjectiveSugar

    Plus, its tagline is "ObjectiveC additions for humans. Ruby style." which should suit OP well ;-)

    My most common use-case is mapping an dictionary returned by a server call to an array of simpler objects e.g. getting an NSArray of NSString IDs from your NSDictionary posts:

    NSArray *postIds = [results map:^NSString*(NSDictionary* post) {
                           return [post objectForKey:@"post_id"];
                       }];
    
    0 讨论(0)
  • 2020-11-28 05:38

    Update: If you're using Swift, see map.


    BlocksKit is an option:

    NSArray *new = [stringArray bk_map:^id(NSString *obj) { 
        return [obj stringByAppendingString:@".png"]; 
    }];
    

    Underscore is another option. There is a map function, here is an example from the website:

    NSArray *tweets = Underscore.array(results)
        // Let's make sure that we only operate on NSDictionaries, you never
        // know with these APIs ;-)
        .filter(Underscore.isDictionary)
        // Remove all tweets that are in English
        .reject(^BOOL (NSDictionary *tweet) {
            return [tweet[@"iso_language_code"] isEqualToString:@"en"];
        })
        // Create a simple string representation for every tweet
        .map(^NSString *(NSDictionary *tweet) {
            NSString *name = tweet[@"from_user_name"];
            NSString *text = tweet[@"text"];
    
            return [NSString stringWithFormat:@"%@: %@", name, text];
        })
        .unwrap;
    
    0 讨论(0)
  • 2020-11-28 05:38

    I've no idea what that bit of Ruby does but I think you are looking for NSArray's implementation of -valueForKey:. This sends -valueForKey: to every element of the array and returns an array of the results. If the elements in the receiving array are NSDictionaries, -valueForKey: is nearly the same as -objectForKey:. It will work as long as the key doesn't start with an @

    0 讨论(0)
  • 2020-11-28 05:41

    Swift introduces a new map function.

    Here is an example from the documentation:

    let digitNames = [
        0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
        5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
    ]
    let numbers = [16, 58, 510]
    
    let strings = numbers.map {
        (var number) -> String in
        var output = ""
        while number > 0 {
            output = digitNames[number % 10]! + output
            number /= 10
        }
        return output
    }
    // strings is inferred to be of type String[]
    // its value is ["OneSix", "FiveEight", "FiveOneZero"]
    

    The map function takes a closure which returns a value of any type and maps the existing values in the array to instances of this new type.

    0 讨论(0)
  • 2020-11-28 05:43

    I think valueForKeyPath is a good choice.

    Sit below has very cool examples. Hopes it is helpful.

    http://kickingbear.com/blog/archives/9

    Some example:

    NSArray *names = [allEmployees valueForKeyPath: @"[collect].{daysOff<10}.name"];
    NSArray *albumCovers = [records valueForKeyPath:@"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];
    
    0 讨论(0)
提交回复
热议问题