Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Key-Value Coding Aggregation Operations on Collections

DZone's Guide to

Key-Value Coding Aggregation Operations on Collections

Stop overlooking Key-Value Coding! Use this handy reference, because if you have ever worked with SQL queries and the aggregate functions, you know you need it.

· Mobile Zone
Free Resource

Discover how to focus on operators for Reactive Programming and how they are essential to react to data in your application.  Brought to you in partnership with Wakanda

If you have ever worked with SQL queries and the aggregate functions (or in worst case with spreadsheet applications like Excel or Numbers), this topic will be familiar to you.

It is usually overlooked, but the Key-Value Coding can also benefit from those functions on collections, like NSArray or NSSet. Obviously, the type should support those operations, for example, it would be barely successful to ask for sum on a set containing NSStrings.

Aggregate functions in Key-Value Coding

Let’s take a look what basic aggregation operations we have, similar to the SQL: @count, @sum, @avg, @max, and @min. There are also other operations, for the full list, you can check the documentation.

The key point here is the same method used for the Key-Value Coding, the valueForKeyPath:. If you want to use the aggregate functions on any set, you should use [anySet valueForKeyPath:@[email protected]_function.key”];. Notice, that we are using the @ symbol before the aggregate.

However, @count doesn’t make sense for me, as you can always send the count message to the set, the others could be really interesting and helpful.

Aggregate!

Let see some basic example for NSNumbers and dates. Obviously, @avg and @sum will fail on NSDates.

        NSArray *numbers = @[@6,@4,@7,@90];
        NSNumber *maxNumber = [numbers valueForKeyPath:@"@max.self"];
        NSNumber *minNumber = [numbers valueForKeyPath:@"@min.self"];
        NSNumber *sumOfNumbers = [numbers valueForKeyPath:@"@sum.self"];
        NSNumber *avgOfNumbers = [numbers valueForKeyPath:@"@avg.self"];

        NSLog(@"\nmin: %@\nmax: %@\nsum: %@\navg: %@", minNumber, maxNumber, sumOfNumbers, avgOfNumbers);

        NSDate *today = [NSDate date];
        NSArray *dates = @[today,
                               [today dateByAddingTimeInterval: -86400.0],
                               [today dateByAddingTimeInterval: 86400.0]
                               ];

        NSDate *maxDate = [dates valueForKeyPath:@"@max.self"];
        NSDate *minDate = [dates valueForKeyPath:@"@min.self"];

        NSLog(@"\nminDate: %@\nmaxDate: %@\n", maxDate, minDate);

Since the aggregate should be applied on the set, which contains the atomic structures, I used .self after the aggregate function.

The thing is getting more interesting, when you are using array of Objects, for example:

#import <Foundation/Foundation.h>
#import "PMOLottoNumbers.h"

@interface PMOTransaction : NSObject

@property NSString *name;
@property NSNumber *amount;
@property NSDate *transactionDate;

@end

@implementation PMOTransaction

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {

        PMOTransaction *transaction1 = [[PMOTransaction alloc] init];

        transaction1.name = @"Mark";
        transaction1.amount = @1000;
        transaction1.transactionDate = today;

        PMOTransaction *transaction2 = [[PMOTransaction alloc] init];

        transaction2.name = @"Mark";
        transaction2.amount = @500;
        transaction2.transactionDate = [today dateByAddingTimeInterval: -86400.0];

        PMOTransaction *transaction3 = [[PMOTransaction alloc] init];

        transaction3.name = @"Abella";
        transaction3.amount = @99999;
        transaction3.transactionDate = [today dateByAddingTimeInterval: 86400.0];

        NSArray *transactions = @[transaction1, transaction2, transaction3];

        NSNumber *maxAmount = [transactions valueForKeyPath:@"@max.amount"];
        NSNumber *minAmount = [transactions valueForKeyPath:@"@min.amount"];
        NSNumber *sumOfAmount = [transactions valueForKeyPath:@"@sum.amount"];
        NSNumber *avgOfAmount = [transactions valueForKeyPath:@"@avg.amount"];

        NSLog(@"\nminAmount: %@\nmaxAmount: %@\nsumOfAmount: %@\navgOfAmount: %@\n", minAmount, maxAmount, sumOfAmount, avgOfAmount);

        NSString *minName = [transactions valueForKeyPath:@"@min.name"];
        NSString *maxName = [transactions valueForKeyPath:@"@max.name"];
        NSString *countName = [transactions valueForKeyPath:@"@count.name"];

        NSLog(@"\nminName: %@\nmaxName: %@\ncountName: %@", minName, maxName, countName);

    }
    return 0;
}

As you can see I created a really basic class (PMOTransaction), and 3 instances, which I added to a collection. Then I used the property names as keys, and applied the aggregate on them.

I hope this small example helps to you out in some cases when you need the minimum or a maximum from a collection.

Learn how divergent branches can appear in your repository and how to better understand why they are called “branches".  Brought to you in partnership with Wakanda

Topics:
key-value ,queries ,aggregate function ,mobile ,ios

Published at DZone with permission of Peter Molnar, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}