Objective-C에서 NSArray를 새 NSArray로 필터링


121

나는이 NSArray나는 새를 만들 싶습니다 NSArray특정 기준을 충족 원래 배열에서 객체. 기준은를 반환하는 함수에 의해 결정됩니다 BOOL.

을 만들고 NSMutableArray소스 배열을 반복하고 필터 함수가 허용하는 객체를 복사 한 다음 변경 불가능한 버전을 만들 수 있습니다.

더 좋은 방법이 있습니까?

답변:


140

NSArray및 NSMutableArray필터 어레이 목차 방법을 제공한다. 지정된 술어와 일치하는 수신자의 오브젝트를 포함하는 새 배열을 리턴하는 filtersArrayUsingPredicate : 를 NSArray제공합니다 . filterUsingPredicate : 추가 : 지정된 조건 자에 대해 수신자의 콘텐츠를 평가하고 일치하는 개체 만 남겨 둡니다. 이러한 방법은 다음 예제에 설명되어 있습니다.NSMutableArray

NSMutableArray *array =
    [NSMutableArray arrayWithObjects:@"Bill", @"Ben", @"Chris", @"Melissa", nil];

NSPredicate *bPredicate =
    [NSPredicate predicateWithFormat:@"SELF beginswith[c] 'b'"];
NSArray *beginWithB =
    [array filteredArrayUsingPredicate:bPredicate];
// beginWithB contains { @"Bill", @"Ben" }.

NSPredicate *sPredicate =
    [NSPredicate predicateWithFormat:@"SELF contains[c] 's'"];
[array filteredArrayUsingPredicate:sPredicate];
// array now contains { @"Chris", @"Melissa" }

84
저는 Papa Smurf의 팟 캐스트를 들었고 Papa Smurf는 답변이 StackOverflow에 있어야 커뮤니티가 평가하고 개선 할 수 있다고 말했습니다.
— willc2

10
@mmalc-아마도 더 적절할 수도 있지만 바로 여기에서 보는 것이 더 편리합니다.
— Bryan

5
NSPredicate는 죽었습니다. cf. 아래 내 대답.
— Clay Bridges

contains [c]는 무슨 뜻인가요? 나는 항상 [c]를 보지만 그것이 무엇을하는지 이해하지 못합니까?
— user1007522

3
@ user1007522, [c]는 대소 문자를 구분하지 않습니다
— jonbauer 2014-10-22

104

이 작업을 수행하는 방법에는 여러 가지가 있지만 가장 가까운 방법은 확실히 다음을 사용하고 있습니다 [NSPredicate predicateWithBlock:].

NSArray *filteredArray = [array filteredArrayUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id object, NSDictionary *bindings) {
    return [object shouldIKeepYou];  // Return YES for each object you want in filteredArray.
}]];

나는 그것이 얻는 것처럼 간결하다고 생각합니다.


빠른:

NSArraySwift에서 s로 작업하는 사람들 은 이보다 간결한 버전을 선호 할 수 있습니다 .

nsArray = nsArray.filter { $0.shouldIKeepYou() }

filterArray( NSArray은 암시 적으로 Swift에 연결 되는 방법입니다 Array). 하나의 인수를 취합니다 : 배열에서 하나의 객체를 취하고 Bool. 클로저 true에서 필터링 된 배열에서 원하는 객체를 반환하십시오 .


1
여기서 NSDictionary * bindings의 역할은 무엇입니까?
— Kaitain

@Kaitain 바인딩은 NSPredicate predicateWithBlock:API에 필요 합니다.
— ThomasW 2015 년

@Kaitain bindings사전에는 템플릿에 대한 변수 바인딩이 포함될 수 있습니다.
— 아민 Negm - 아 와드

허용 대답보다 훨씬 더 유용합니다 :) 복잡한 객체를 처리 할 때
— 벤 Leggiero

47

Clay Bridges의 답변에 따라 다음은 블록을 사용한 필터링의 예입니다 ( yourArray배열 변수 이름과 testFunc테스트 함수 이름으로 변경 ).

yourArray = [yourArray objectsAtIndexes:[yourArray indexesOfObjectsPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
    return [self testFunc:obj];
}]];

마지막으로 블록 필터링을 언급 할뿐만 아니라이를 수행하는 방법에 대한 좋은 예도 제공합니다. 감사.
— Krystian

나는이 대답을 좋아한다. filteredArrayUsingPredicate더 간결 하지만 어떤 술어도 사용하지 않는다는 사실은 목적을 모호하게합니다.
— James Perih

이것이 가장 현대적인 방법입니다. 개인적으로 나는 특정 시점에서 API에서 사라진 오래된 속기 "objectsPassingTest"를 그리워합니다. 여전히 이것은 빠르고 좋습니다. 나는 NSPredicate를 좋아합니다. 그러나 더 무거운 망치가 필요한 다른 것들에 대해서는
— Motti Shneor

이제 오류가 발생합니다 Implicit conversion of 'NSUInteger' (aka 'unsigned long') to 'NSIndexSet * _Nonnull' is disallowed with ARC... NSIndexSets 예상
— anoop4real

@ anoop4real, 당신이 언급 한 경고의 원인 indexOfObjectPassingTest은 indexesOfObjectsPassingTest. 놓치기 쉽지만 큰 차이점 :)
— pckill

46

OS X 10.6 / iOS 4.0 이상인 경우 NSPredicate보다 블록을 사용하는 것이 좋습니다. 보다-[NSArray indexesOfObjectsPassingTest:] 또는 편리한 추가 자신의 범주를 쓰기 -select:또는 -filter:방법 ( 예 ).

다른 사람이 해당 카테고리를 작성하고 테스트하는 등의 작업을 원하십니까? BlocksKit ( array docs )을 확인하십시오 . 그리고 거기에 많은 예를 들어 검색 말하자면 찾을 수 더 많은 예제, "NSArray를 블록 카테고리 선택이" .


5
예를 들어 답변을 확장 해 주시겠습니까? 블로그 웹 사이트는 가장 필요할 때 죽는 경향이 있습니다.
— Dan Abramov

8
링크 부패에 대한 보호는 링크를 더 추가하는 것이 아니라 링크 된 기사에서 관련 코드를 발췌하는 것입니다. 링크를 유지하되 예제 코드를 추가하십시오.
— toolbear

3
@ClayBridges 코코아에서 필터링하는 방법을 찾는이 질문을 찾았습니다. 귀하의 답변에는 코드 샘플이 없기 때문에 블록이 필요한 것을 달성하지 못함을 확인하기 위해 링크를 파헤치는 데 약 5 분이 걸렸습니다. 코드가 답에 있었다면 아마 30 초가 걸렸을 것입니다. 이 답변은 실제 코드 없이는 덜 유용합니다.
— N_A

1
@mydogisbox 외 : 여기에는 답이 4 개뿐이므로 자신 만의 반짝이고 우수한 코드 샘플링 답변을위한 충분한 공간이 있습니다. 나는 내 것이 만족 스럽기 때문에 내버려 두십시오.
— Clay Bridges

2
mydogisbox가 바로 여기에 있습니다. 링크를 제공하는 것뿐이라면 링크를 더 추가하더라도 실제로는 답이 아닙니다. meta.stackexchange.com/questions/8231을 참조하세요 . 리트머스 테스트 : 당신의 대답은 그 자체로 설 수 있습니까, 아니면 어떤 가치가있는 링크를 클릭해야합니까? 특히, "NSPredicate보다 블록을 사용하는 것이 더 낫다"고 말하지만 실제로 그 이유를 설명하지는 않습니다.
— Robert Harvey

16

객체가 모두 유사한 유형이라고 가정하면 기준에 사용중인 함수를 호출하는 기본 클래스의 범주로 메서드를 추가 할 수 있습니다. 그런 다음 해당 메서드를 참조하는 NSPredicate 개체를 만듭니다.

일부 범주에서 함수를 사용하는 방법을 정의하십시오.

@implementation BaseClass (SomeCategory)
- (BOOL)myMethod {
    return someComparisonFunction(self, whatever);
}
@end

그런 다음 필터링 할 위치 :

- (NSArray *)myFilteredObjects {
    NSPredicate *pred = [NSPredicate predicateWithFormat:@"myMethod = TRUE"];
    return [myArray filteredArrayUsingPredicate:pred];
}

물론 함수가 클래스 내에서 도달 할 수있는 속성과 만 비교하는 경우 함수의 조건을 조건 자 문자열로 변환하는 것이 더 쉬울 수 있습니다.


이 답변은 우아하고 짧기 때문에 가장 기본적인 것에 대해 NSPredicate를 공식화하는 방법, 즉 속성 및 부울 메서드에 액세스하는 방법을 다시 배울 필요가 있기 때문에이 답변을 좋아했습니다. 래퍼도 필요 없다고 생각합니다. 간단한 [myArray filtersArrayUsingPredicate : [NSPredicate predicateWithFormat : @ "myMethod = TRUE"]]; 충분합니다. 감사! (나는 대안도 좋아하지만 이것은 좋은 것입니다).
— Motti Shneor

3

NSPredicate(컬렉션을 필터링 조건을 구성하는 넥스트 스텝의 방법입니다 NSArray, NSSet,NSDictionary ).

예를 들어 두 개의 배열을 고려 arr과 filteredarr:

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

filteredarr = [NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

filterarr에는 문자 c 만 포함 된 항목이 확실히 있습니다.

SQL 배경이 적은 사람들을 쉽게 기억할 수 있도록

*--select * from tbl where column1 like '%a%'--*

1) tbl- > 컬렉션 에서 * 선택

2) '% a %'와 같은 column1- >NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF contains[c] %@",@"c"];

3) select * from tbl where column1 like '% a %' ->

[NSMutableArray arrayWithArray:[arr filteredArrayUsingPredicate:predicate]];

이게 도움이 되길 바란다


2

NSArray + Xh

@interface NSArray (X)
/**
 *  @return new NSArray with objects, that passing test block
 */
- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate;
@end

NSArray + Xm

@implementation NSArray (X)

- (NSArray *)filteredArrayPassingTest:(BOOL (^)(id obj, NSUInteger idx, BOOL *stop))predicate
{
    return [self objectsAtIndexes:[self indexesOfObjectsPassingTest:predicate]];
}

@end

여기에서이 카테고리를 다운로드 할 수 있습니다.


0

이 라이브러리 체크 아웃

https://github.com/BadChoice/Collection

루프를 다시 작성하지 않기 위해 많은 쉬운 배열 함수가 제공됩니다.

따라서 다음을 수행 할 수 있습니다.

NSArray* youngHeroes = [self.heroes filter:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

또는

NSArray* oldHeroes = [self.heroes reject:^BOOL(Hero *object) {
    return object.age.intValue < 20;
}];

0

가장 좋고 쉬운 방법은이 방법을 만들고 배열 및 값을 전달하는 것입니다.

- (NSArray *) filter:(NSArray *)array where:(NSString *)key is:(id)value{
    NSMutableArray *temArr=[[NSMutableArray alloc] init];
    for(NSDictionary *dic in self)
        if([dic[key] isEqual:value])
            [temArr addObject:dic];
    return temArr;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.