Underscore.m

Underscore.m是一个Objective-C小型实用程序库,用于简化常见数据结构的操作。它支持数组和字典的各种处理方法,如筛选、映射、归约等,并提供一系列辅助函数来帮助开发者更高效地进行开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://underscorem.org/

https://github.com/robb/Underscore.m

 

Underscore.m

a functional toolbelt for Objective-C

Underscore.m is a small utility library to facilitate working with common data structures in Objective-C.

It tries to encourage chaining by eschewing the square bracket]]]]]].

It is inspired by the awesome underscore.js. Underscore.m was written by Robert Böhnke and is MIT licensed.

Underscore.m on GitHub

Examples

Consider these Hello World! strings:

NSDictionary *dictionary = @{
  @"en": @"Hello world!",
  @"sv": @"Hej världen!",
  @"de": @"Hallo Welt!",
  @"ja": [NSNull null]
}

Underscore.m makes extracting the strings and capitalizing them a breeze.

NSArray *capitalized = Underscore.dict(dictionary)
  .values
  .filter(Underscore.isString)
  .map(^NSString *(NSString *string) {
    return [string capitalizedString];
  })
  .unwrap;

Underscore.m is especially useful when you deal with structured data from web APIs.

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;

Installation

It is recommended to use CocoaPods to install Underscore.m. Alternatively you can download the code from GitHub.

You may want to alias Underscore to _ to make accessing Underscore.m’s methods more concise.

#import "Underscore.h"
#define _ Underscore

NSArray

The following methods can be used with NSArray and NSMutableArray instances. With Underscore.m’s array methods can use a functional-style syntax as well as chaining to create powerful expressions.

Underscore.m supports the following methods to manipulate arrays:

arrayUnderscore.array(NSArray *array)

Wraps an array in an USArrayWrapper. Use this method if you want to chain multiple operations together. You will need to call unwrap to extract the new array at the end.

NSArray *elements = Underscore.array(array)
    .flatten
    .uniq
    .unwrap;

Since array is meant for chaining, you probably don’t need to keep a reference to the USArrayWrapper.

unwrapwrapper.unwrap

Extracts the array of an USArrayWrapper.

firstUnderscore.first(NSArray *array)

Returns the first element of the array or nil if it is empty.

id first = Underscore.first(array);
lastUnderscore.last(NSArray *array)

Returns the last element of the array or nil if it is empty.

id last = Underscore.last(array);
headUnderscore.head(NSArray *array, NSUInteger n)

Returns the first n elements or all of them, if there are less than n elements in the array.

NSArray *firstThree = Underscore.head(array, 3);
tailUnderscore.tail(NSArray *array, NSUInteger n)

Returns the last n elements or all of them, if there are less than n elements in the array.

NSArray *lastThree = Underscore.tail(array, 3);
indexOfUnderscore.indexOf(NSArray *array, id obj)

Returns the index of the first occurrence of obj in array or NSNotFound, if the element could not be found.

NSUInteger twentySix = Underscore.indexOf(alphabet, @"z");
flattenUnderscore.flatten(NSArray *array)

Recursively flattens the array.

NSArray *arrayOfArrays = @[ @[ @1, @2], @[ @3, @4], @[ @5, @6] ];
NSArray *oneToSix      = Underscore.flatten(arrayOfArrays);
withoutUnderscore.without(NSArray *array, NSArray *values)

Returns all elements not contained in values.

NSArray *oddNumbers = Underscore.without(allNumbers, evenNumbers);
shuffleUnderscore.shuffle(NSArray *array)

Shuffles the array using the Fisher-Yates-Shuffle.

NSArray *shuffled = Underscore.shuffle(array);
reduceUnderscore.reduce(id memo, UnderscoreReduceBlock block)
reduceRightUnderscore.reduceRight(id memo, UnderscoreReduceBlock block)

Reduces the array to a single value using the block.

NSArray *numbers = @[ @1, @2, @3, @4, @5, @6, @7 ];
NSArray *sum     = Underscore.array(numbers)
    .reduce(@0, ^(NSNumber *x, NSNumber *y) {
        return @(x.integerValue + y.integerValue);
    })
    .unwrap;
eachwrapper.each(UnderscoreArrayIteratorBlock block)
arrayEachUnderscore.arrayEach(NSArray *array, UnderscoreArrayIteratorBlock block)

Calls block once with every member of the array. This method returns the same array again, to facilitate chaining.

Functional syntax:

Underscore.arrayEach(objects, ^(id obj) {
    NSLog(@"%@", obj);
});

Chaining:

Underscore.array(objects)
    .each(^(id obj) {
        NSLog(@"%@", obj);
    });
mapwrapper.map(UnderscoreArrayMapBlock block)
arrayMapUnderscore.arrayMap(NSArray *array, UnderscoreArrayMapBlock block)

Calls block once with every element of the array. If the block returns nil, the object is removed from the array. Otherwise, the return-value replaces the object.

Functional syntax:

Underscore.arrayMap(strings, ^(NSString *string) {
    return string.capitalizedString;
});

Chaining:

Underscore.array(strings)
    .map(^(NSString *string) {
        return string.capitalizedString;
    });
pluckUnderscore.pluck(NSArray *array, NSString *keyPath)

Returns an array containing the objects’ values for the given key path.

NSArray *names = Underscore.pluck(users, @"name");
uniqUnderscore.uniq(NSArray *array)

Returns a new array containing all elements of array exactly once.

NSArray *uniques = Underscore.uniq(@[ @1, @1, @2, @3 ]);
findUnderscore.find(NSArray *array, UnderscoreTestBlock test)

Returns an object from the array the passes the test or nil, if none of the elements match.

User *admin = Underscore.find(users, ^BOOL (User *user) {
        return user.isAdmin;
    })
filterUnderscore.filter(NSArray *array, UnderscoreTestBlock test)

Returns all elements that pass the test.

NSArray *dictionaries = Underscore.filter(objects, Underscore.isDictionary);
rejectUnderscore.reject(NSArray *array, UnderscoreTestBlock test)

Returns all elements that fail the test.

NSArray *dictionaries = Underscore.reject(objects, Underscore.isNull);
allUnderscore.all(NSArray *array, UnderscoreTestBlock test)

Returns YES if all elements pass the test.

BOOL onlyStrings = Underscore.all(objets, Underscore.isString);
anyUnderscore.any(NSArray *array, UnderscoreTestBlock test)

Returns YES if any of the elements pass the test.

BOOL containsNull = Underscore.any(objets, Underscore.isNull);

NSDictionary

The following methods can be used with NSDictionary and NSMutableDictionaryinstances. With Underscore.m’s dictionary methods can use a functional-style syntax as well as chaining to create powerful expressions.

Underscore.m supports the following methods to manipulate dictionaries:

dictUnderscore.dict(NSDictionary *dictionary)

Wraps a dictionary in an USDictionaryWrapper. Use this method if you want to chain multiple operations together. You will need to call unwrap to extract the result.

NSDictionary *user = Underscore.dict(data)
    .rejectValues(Underscore.isNull)
    .defaults(@{
        @"avatar":          kDefaultAvatar,
        @"backgroundColor": kDefaultBackgroundColor
    })
    .unwrap;

Since dict is meant for chaining, you probably don’t need to keep a reference to theUSDictionaryWrapper.

unwrapwrapper.unwrap

Extracts the dictionary of an USDictionaryWrapper.

keysUnderscore.keys(NSDictionary *dictionary)

Returns the keys of a dictionary.

NSArray *keys = Underscore.keys(dictionary);

When called on a USDictionaryWrapper, it returns a USArrayWrapper to facilitate chaining.

id key = Underscore.dict(dictionary)
    .keys
    .first;
valuesUnderscore.values(NSDictionary *dictionary)

Returns the values of a dictionary.

NSArray *values = Underscore.values(dictionary);

When called on a USDictionaryWrapper, it returns a USArrayWrapper to facilitate chaining.

id value = Underscore.dict(dictionary)
    .values
    .first;
eachwrapper.each(UnderscoreDictionaryIteratorBlock block)
dictEachUnderscore.each(NSDictionary *dictionary, UnderscoreDictionaryIteratorBlock block)

Calls block once with every key-value pair of the dictionary. This method returns the same dictionary again, to facilitate chaining.

Functional syntax:

Underscore.dictEach(dictionary, ^(id key, id obj) {
    NSLog(@"%@: %@", key, obj);
});

Chaining:

Underscore.dict(objects)
    .each(^(id key, id obj) {
        NSLog(@"%@: %@", key, obj);
    });
mapwrapper.map(UnderscoreDictionaryMapBlock block)
dictMapUnderscore.map(NSDictionary *dictionary, UnderscoreDictionaryMapBlock block)

Calls block once with every key-value pair of he dictionary. If the block returns nil, the key-value-pair is removed from the dictionary. Otherwise, the return-value replaces the value.

Functional syntax:

Underscore.dictMap(dictionary, ^(id key, id obj) {
    if ([obj isKindOfClass:NSString.class]) {
        return [(NSString *)obj capitalizedString]
    } else {
        return obj;
    });

Chaining:

Underscore.dict(dictionary)
    .map(^(id key, id obj) {
        if ([obj isKindOfClass:NSString.class]) {
            return [(NSString *)obj capitalizedString]
        } else {
            return obj;
        }
    });
pickUnderscore.pick(NSDictionary *dictionary, NSArray *keys)

Returns a copy of dictionary that contains only the keys contained in keys.

NSDictionary *subset = Underscore.pick(info, @[ @"name", @"email", @"address" ]);
extendUnderscore.extend(NSDictionary *destination, NSDictionary *source)

Returns a dictionary that contains a union of key-value-pairs of destination andsource. Key-value-pairs of source will have precedence over those taken fromdestination.

NSDictionary *dictionary = Underscore.extend(user, @{ @"age": @50 });
defaultsUnderscore.defaults(NSDictionary *dictionary, NSDictionary *defaults)

Returns a dictionary that contains a union of key-value-pairs of dictionary anddefaults. Key-value-pairs of destination will have precedence over those taken fromdefaults.

NSDictionary *dictionary = Underscore.defaults(user, @{ @"avatar": kDefaultAvatar });

A common use case for defaults is sanitizing data with known values.

NSDictionary *user = Underscore.dict(data)
    .rejectValues(Underscore.isNull)
    .defaults(@{
        @"avatar":          kDefaultAvatar,
        @"backgroundColor": kDefaultBackgroundColor
    })
    .unwrap;
filterKeysUnderscore.filterKeys(NSDictionary *dictionary, UnderscoreTestBlock test)

Returns a dictionary that only contains the key-value-pairs whose keys pass test.

NSDictionary *soundcloudRelated = Underscore.filterKeys(data, ^BOOL (NSString *key) {
    return [key hasPrefix:@"soundcloud-"];
});
filterValuesUnderscore.filterValues(NSDictionary *dictionary, UnderscoreTestBlock test)

Returns a dictionary that only contains the key-value-pairse whose values passtest.

NSDictionary *numericValues = Underscore.filterValues(data, Underscore.isNumber);
rejectKeysUnderscore.rejectKeys(NSDictionary *dictionary, UnderscoreTestBlock test)

Returns a dictionary that only contains the key-value-pairs whose keys fail test.

NSDictionary *safe = Underscore.rejectKeys(data, ^BOOL (NSString *key) {
    return [blackList containsObject:key];
});
rejectValuesUnderscore.rejectValues(NSDictionary *dictionary, UnderscoreTestBlock test)

Returns a dictionary that only contains the key-value-pairs whose values fail test.

NSDictionary *noNulls = Underscore.rejectValues(data, Underscore.isNull);

Helpers

negateUnderscore.negate(UnderscoreTestBlock block)

Returns a block that negates block

id notNull = Underscore.find(array, Underscore.negate(Underscore.isNull));
isEqualUnderscore.isEqual(id obj)

Returns a block that returns YES whenever it is called with an object equal to obj.

BOOL containsNeedle = Underscore.any(haystack, Underscore.isEqual(@"needle"));
isArrayUnderscore.isArray

A block that returns YES if it is called with an NSArray.

isDictionaryUnderscore.isDictionary

A block that returns YES if it is called with an NSDictionary.

isNullUnderscore.isNull

A block that returns YES if it is called with an NSNull.

isNumberUnderscore.isNumber

A block that returns YES if it is called with an NSNumber.

isStringUnderscore.isString

A block that returns YES if it is called with an NSString.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值