Thomas Besnehard
Thomas Besnehard

Reputation: 2095

Get list of Values for an NSArray of NSDictionary

I've got the following NSArray :

NSArray myArray = @[@{@300:@"5 min"},
                    @{@900:@"15 min"},
                    @{@1800:@"30 min"},
                    @{@3600:@"1 hour"}];

I want the list of value of my dictionaries :

@[@"5 min",@"15 min",@"30 min",@"1 hour"]

And the list of key of my dictionaries :

@[@300, @900, @1800, @3600]

What is the best way to do that ? I was thinking about predicate, but I don't know how to use it ?

Upvotes: 4

Views: 6480

Answers (4)

Monolo
Monolo

Reputation: 18253

Without some code to show how you'd want to go about this it is difficult to be sure exactly what you are after, and there is a bit of confusion in the question.

First, a predicate is exactly that - a statement that can be proven true or false. Predicates are hence used in logic expressions, including those employed implicitly in database queries - such as Core Data.

That is not what you want, if I read your question correctly. What you want is to reduce the complexity of your data model, removing some excess (one would hope) information in the process. A sort of flattening of an array of dictionaries.

Fair enough.

I can also see how the confusion with predicates came about - they are most often constructed using Key-Value Coding. KVC, as it is also known, is a very powerful technique that can accomplish what you are after. It just does not have much to do with a logic statement.

Having cleared that up, with KVC you can do what you want, and with minimal fuss. It goes like this:

NSArray *values = [myArray valueForKeyPath: @"@unionOfArrays.@allValues"];

NSArray *keys   = [myArray valueForKeyPath: @"@unionOfArrays.@allKeys"];

A brief explanation might be in order:

The results that we want are

  1. All the values (or keys) of each dictionary, obtaining an array of arrays of values (or keys)
  2. Then we want to flatten these arrays into a single array.

To obtain all values (or keys) from a dictionary using KVC, the special key is @allValues or @allKeys, respectively.

The @unionOfArrays operator makes a union of the arrays obtained from the expression that follows it, i.e., flattens it into the array you wanted.

The price you pay for this coding simplicity is that you have to use KVC key paths with collection operators, which are just strings in your code. You therefore lose any help from the compiler with syntax and it doesn't check that the keys you enter exist in the objects. Similarly, the debugger and error messages are unhelpful if you mistype or use the wrong operator, for instance.

Upvotes: 9

Mick MacCallum
Mick MacCallum

Reputation: 130193

@johnyu's answers is technically correct, but I don't see any reason to include the secondary loop, especially if the data structure will remain the same.

NSArray *myArray = @[@{@300:@"5 min"},
                     @{@900:@"15 min"},
                     @{@1800:@"30 min"},
                     @{@3600:@"1 hour"}];

NSMutableArray *arrayOfValues = [NSMutableArray new];
NSMutableArray *arrayOfKeys = [NSMutableArray new];

for (NSDictionary *dictionary in myArray) {
    [arrayOfValues addObject:dictionary.allValues[0]];
    [arrayOfKeys addObject:dictionary.allKeys[0]];
}

NSLog(@"%@",arrayOfKeys);
NSLog(@"%@",arrayOfValues);

Upvotes: 1

johnyu
johnyu

Reputation: 2151

Try this:

NSArray *myArray = @[@{@300:@"5 min"},
                    @{@900:@"15 min"},
                    @{@1800:@"30 min"},
                    @{@3600:@"1 hour"}];
NSMutableArray *keyArray = [[NSMutableArray alloc] init];
NSMutableArray *valueArray = [[NSMutableArray alloc] init];
for (NSDictionary *dictionary in myArray) {
    for (NSString *key in dictionary) {
        [keyArray addObject:key];
        [valueArray addObject:[dictionary objectForKey:key]];
    }
}

Upvotes: 0

Nanda
Nanda

Reputation: 722

You can use dictionary property allValues to get all values of dictionary.

Try this code in your case

NSArray *myArray = @[@{@300:@"5 min"},
                     @{@900:@"15 min"},
                     @{@1800:@"30 min"},
                     @{@3600:@"1 hour"}];
NSMutableArray *arr = [NSMutableArray array];
for (NSDictionary *dict in myArray) {
    [arr addObject:[[dict allValues] objectAtIndex:0]];
}
NSLog(@"%@",arr);

Note : Make sure you have only one value in each dictionary. it will return

[

5 min,

15 min,

30 min,

1 hour

]

Upvotes: 1

Related Questions