数组和集合的高级用法
来源:互联网 发布:charles 破解版 mac 编辑:程序博客网 时间:2024/04/30 01:10
转自: http://nshipster.com/kvc-collection-operators/
KVC Collection Operators
Written by Mattt Thompson on Dec 3rd, 2012
Rubyists laugh at Objective-C's bloated syntax.
Although we lost a few pounds over the summer with our sleek new object literals, those Red-headed bullies still taunt us with their map
one-liners and their fancy Symbol#to_proc
.
Really, a lot of how elegant (or clever) a language is comes down to how well it avoids loops. for
,while
; even fast enumeration expressions are a drag. No matter how you sugar-coat them, loops will be a block of code that does something that is much simpler to describe in natural language.
"get me the average salary of all of the employees in this array", versus...
double totalSalary = 0.0;for (Employee *employee in employees) { totalSalary += [employee.salary doubleValue];}double averageSalary = totalSalary / [employees count];
Meh.
Fortunately, Key-Value Coding gives us a much more concise--almost Ruby-like--way to do this:
[employees valueForKeyPath:@"@avg.salary"];
KVC Collection Operators allows actions to be performed on a collection using key path notation invalueForKeyPath:
. Any time you see @
in a key path, it denotes a particular aggregate function whose result can be returned or chained, just like any other key path.
Collection Operators fall into one of three different categories, according to the kind of value they return:
- Simple Collection Operators return strings, numbers, or dates, depending on the operator.
- Object Operators return an array.
- Array and Set Operators return an array or set, depending on the operator.
The best way to understand how these work is to see them in action. Consider a Product
class, and a products
array with the following data:
@interface Product : NSObject@property NSString *name;@property double price;@property NSDate *launchedOn;@end
Key-Value Coding automatically boxes and un-boxes scalars into
NSNumber
orNSValue
as necessary to make everything work.
Simple Collection Operators
@count
: Returns the number of objects in the collection as anNSNumber
.@sum
: Converts each object in the collection to adouble
, computes the sum, and returns the sum as anNSNumber
.@avg
: Takes thedouble
value of each object in the collection, and returns the average value as anNSNumber
.@max
: Determines the maximum value usingcompare:
. Objects must support comparison with one another for this to work.@min
: Same as@max
, but returns the minimum value in the collection.
Example:
[products valueForKeyPath:@"@count"]; // 4[products valueForKeyPath:@"@sum.price"]; // 3526.00[products valueForKeyPath:@"@avg.price"]; // 881.50[products valueForKeyPath:@"@max.price"]; // 1699.00[products valueForKeyPath:@"@min.launchedOn"]; // June 11, 2012
Pro Tip: To get the aggregate value of an array or set of
NSNumber
s, you can simply passself
as the key path after the operator, e.g.[@[@(1), @(2), @(3)] valueForKeyPath:@"@max.self"]
(/via @davandermobile, citing Objective Sea)
Object Operators
Let's say we have an inventory
array, representing the current stock of our local Apple store (which is running low on iPad Mini, and doesn't have the new iMac, which hasn't shipped yet):
NSArray *inventory = @[iPhone5, iPhone5, iPhone5, iPadMini, macBookPro, macBookPro];
@unionOfObjects
/@distinctUnionOfObjects
: Returns an array of the objects in the property specified in the key path to the right of the operator.@distinctUnionOfObjects
removes duplicates, whereas@unionOfObjects
does not.
Example:
[inventory valueForKeyPath:@"@unionOfObjects.name"]; // "iPhone 5", "iPhone 5", "iPhone 5", "iPad Mini", "MacBook Pro", "MacBook Pro"[inventory valueForKeyPath:@"@distinctUnionOfObjects.name"]; // "iPhone 5", "iPad Mini", "MacBook Pro"
Array and Set Operators
Array and Set Operators are similar to Object Operators, but they work on collections of NSArray
and NSSet
.
This would be useful if we were to, for example, compare the inventory of several stores, sayappleStoreInventory
, (same as in the previous example) and verizonStoreInventory
(which sells iPhone 5 and iPad Mini, and has both in stock).
@distinctUnionOfArrays
/@unionOfArrays
: Returns an array containing the combined values of each array in the collection, as specified by the key path to the right of the operator. As you'd expect, thedistinct
version removes duplicate values.@distinctUnionOfSets
: Similar to@distinctUnionOfArrays
, but it expects anNSSet
containingNSSet
objects, and returns anNSSet
. Because sets can't contain duplicate values anyway, there is only thedistinct
operator.
Example:
[@[appleStoreInventory, verizonStoreInventory] valueForKeyPath:@"@distinctUnionOfArrays.name"]; // "iPhone 5", "iPad Mini", "MacBook Pro"
This is Probably a Terrible Idea
Curiously, Apple's documentation on KVC collection operators goes out of its way to make the following point:
Note: It is not currently possible to define your own collection operators.
This makes sense to spell out, since that's what most people are thinking about once they see collection operators for the first time.
However, as it turns out, it is actually possible, with a little help from our friend, objc/runtime
.
Guy English has a pretty amazing post wherein he swizzles valueForKeyPath:
to parse a custom-defined DSL, which extends the existing offerings to interesting effect:
NSArray *names = [allEmployees valueForKeyPath: @"[collect].{daysOff<10}.name"];
This code would get the names of anyone who has taken fewer than 10 days off (to remind them to take a vacation, no doubt!).
Or, taken to a ridiculous extreme:
NSArray *albumCovers = [records valueForKeyPath:@"[collect].{artist like 'Bon Iver'}.<NSUnarchiveFromDataTransformerName>.albumCoverImageData"];
Eat your heart out, Ruby. This one-liner filters a record collection for artists whose name matches "Bon Iver", and initializes an NSImage
from the album cover image data of the matching albums.
Is this a good idea? Probably not. (NSPredicate
is rad, and breaking complicated logic up is under-rated)
Is this insanely cool? You bet! This clever example has shown a possible direction for future Objective-C DSLs and meta-programming.
KVC Collection Operators are a must-know for anyone who wants to save a few extra lines of code and look cool in the process.
While scripting languages like Ruby boast considerably more flexibility in its one-liner capability, perhaps we should take a moment to celebrate the restraint built into Objective-C and Collection Operators. After all, Ruby is hella slow, amiright? </troll>
- 数组和集合的高级用法
- JavaScript数组的高级用法-reduce和reduceRight详解
- JavaScript数组的高级用法-reduce和reduceRight详解
- 一维数组的高级用法
- PHP 数组的一些高级用法
- Java中list集合的交集和差集的用法和如何将数组转换为集合的方法
- 数组和集合的整理
- 数组和集合的整理
- 数组和集合的排序
- 集合和数组的异同?
- 数组和集合的排序
- 集合和数组的区别
- Java的数组和集合
- 集合和数组的区别
- 集合和数组的比较
- 数组和集合的区别
- 数组和集合的区别
- Java的数组和集合
- Go语言学习1:开发环境安装
- android中Intent传值与Bundle传值的区别详解
- 设置body的背景图片在网页的顶部居中
- JS 获取select (多选下拉)中所选中的值
- 生命,因追逐梦想而精彩
- 数组和集合的高级用法
- iOS图片旋转
- Red and Black
- HTTP断点续传
- hdu 4310 hero
- AS3人物引擎 人物行走
- 数据库隔离级别总结
- gsensor
- Hud 1213 How Many Tables[简单并查集]