[ios] Objective-C의 NSMutableArray에서 중복 값을 제거하는 가장 좋은 방법은 무엇입니까?

Objective-C NSString에서 중복 값 ( ) 을 제거하는 가장 좋은 방법은 NSMutableArray무엇입니까?

이것이 가장 쉽고 올바른 방법입니까?

uniquearray = [[NSSet setWithArray:yourarray] allObjects];



답변

당신 NSSet이 다시 객체의 순서에 대한 걱정,하지만하지 않는 경우 당신은 순서에 대해 걱정하지 않는 경우 접근 방법은 왜 당신은에 저장되지 않고, 최고 NSSet와 함께 시작?

2009 년에 아래 답변을 썼습니다. 2011 년에 Apple NSOrderedSet은 iOS 5 및 Mac OS X 10.7에 추가되었습니다 . 알고리즘은 이제 두 줄의 코드입니다.

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];

주문이 걱정되고 iOS 4 또는 이전 버전에서 실행중인 경우 배열 사본을 반복하십시오.

NSArray *copy = [mutableArray copy];
NSInteger index = [copy count] - 1;
for (id object in [copy reverseObjectEnumerator]) {
    if ([mutableArray indexOfObject:object inRange:NSMakeRange(0, index)] != NSNotFound) {
        [mutableArray removeObjectAtIndex:index];
    }
    index--;
}
[copy release];


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 NSArray 주문에 신경 쓰지 않는다면 중복을 제거하는보다 우아한 방법이 있습니다.

Key Value Coding의 Object Operators를 사용 하면 다음과 같이 할 수 있습니다.

uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];

마찬가지로 AnthoPak이 또한 주목 그 속성에 기초하여 중복을 제거하는 것이 가능하다. 예를 들면 다음과 같습니다.@distinctUnionOfObjects.name


답변

예, NSSet을 사용하는 것이 현명한 방법입니다.

Jim Puls의 답변에 추가하려면 순서를 유지하면서 중복을 제거하는 다른 방법이 있습니다.

// Initialise a new, empty mutable array 
NSMutableArray *unique = [NSMutableArray array];

for (id obj in originalArray) {
    if (![unique containsObject:obj]) {
        [unique addObject:obj];
    }
}

본질적으로 Jim과 동일한 접근 방법이지만 원본에서 복제본을 삭제하는 대신 고유 한 항목을 새로운 가변 배열에 복사합니다. 이것은 많은 중복을 가진 큰 배열 (전체 배열의 사본을 만들 필요가 없음)의 경우 약간 더 메모리 효율적이며, 제 생각에는 좀 더 읽기 쉽습니다.

두 경우 모두 대상 배열에 항목이 이미 포함되어 있는지 ( containsObject:내 예제 또는 indexOfObject:inRange:Jim의 경우에) 확인하면 큰 배열에는 잘 맞지 않습니다. 이러한 검사는 O (N) 시간에 실행됩니다. 즉, 원래 배열의 크기를 두 배로 늘리면 각 검사 를 실행하는 데 두 배의 시간이 걸립니다. 배열의 각 객체에 대해 검사를 수행하므로 더 비싼 검사를 더 많이 실행하게됩니다. 전체 알고리즘 (광산과 Jim 모두)은 O (N 2 ) 시간에 실행되며 원래 배열이 커짐에 따라 빠르게 비싸집니다.

NSMutableSetNSSet 조회가 O (N)가 아닌 O (1)이기 때문에 이를 O (N) 시간으로 낮추려면 a 를 사용하여 이미 새 배열에 추가 된 항목의 레코드를 저장할 수 있습니다 . 즉, 요소가 NSSet의 멤버인지 여부를 확인하면 세트에있는 요소 수에 관계없이 동일한 시간이 걸립니다.

이 접근법을 사용하는 코드는 다음과 같습니다.

NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];

for (id obj in originalArray) {
    if (![seen containsObject:obj]) {
        [unique addObject:obj];
        [seen addObject:obj];
    }
}

그래도 여전히 조금 낭비적인 것 같습니다. 우리는 원래 배열이 변경 가능하다는 질문이 명백해지면 여전히 새로운 배열을 생성하고 있으므로 중복 제거하고 메모리를 절약 할 수 있어야합니다. 이 같은:

NSMutableSet *seen = [NSMutableSet set];
NSUInteger i = 0;

while (i < [originalArray count]) {
    id obj = [originalArray objectAtIndex:i];

    if ([seen containsObject:obj]) {
        [originalArray removeObjectAtIndex:i];
        // NB: we *don't* increment i here; since
        // we've removed the object previously at
        // index i, [originalArray objectAtIndex:i]
        // now points to the next object in the array.
    } else {
        [seen addObject:obj];
        i++;
    }
}

업데이트 : 유리 니야 조프 (Yuri Niyazov) 아마도 O (N) 시간에 실행 되기 때문에 마지막 대답은 실제로 O (N 2 ) 에서 실행된다고 지적했습니다removeObjectAtIndex: .

(우리는 그것이 어떻게 구현되는지 알지 못하기 때문에 “아마도”라고 말하지만 가능한 한 구현은 인덱스 X에서 객체를 삭제 한 후 메소드가 인덱스 X + 1에서 배열의 마지막 객체까지 모든 요소를 ​​반복한다는 것입니다 , 이전 인덱스로 이동합니다.이 경우 실제로 O (N) 성능입니다.)

그래서 뭘 할건데? 상황에 따라 다릅니다. 대규모 배열이 있고 적은 수의 복제본 만 기대하는 경우 전체 중복 제거 기능이 제대로 작동하여 중복 배열을 구축하지 않아도됩니다. 중복이 많이 예상되는 어레이가있는 경우 별도의 중복 제거 된 어레이를 구축하는 것이 가장 좋은 방법 일 것입니다. 여기서의 탈취는 big-O 표기법은 알고리즘의 특성만을 설명하며 주어진 상황에 가장 적합한 것을 명확하게 알려주지는 않습니다.


답변

iOS 5 이상 (전체 iOS 환경을 대상으로하는)을 대상으로하는 경우 가장 좋습니다 NSOrderedSet. 중복을 제거하고의 순서를 유지합니다 NSArray.

그냥 해

NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];

이제 고유 한 NSArray로 다시 변환 할 수 있습니다

NSArray *uniqueArray = orderedSet.array;

이 같은있는 NSArray 같은 동일한 방법을 가지고 있기 때문에 또는 단지 orderedSet를 사용 objectAtIndex:, firstObject등등합니다.

회원 가입 확인 contains은 회원 가입 보다 더 빠릅니다 NSOrderedSet.NSArray

자세한 체크 아웃을 위해 NSOrderedSet 참조


답변

OS X v10.7 이상에서 사용 가능합니다.

주문이 걱정되는 경우 올바른 방법

NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];

다음은 NSArray에서 중복 값을 순서대로 제거하는 코드입니다.


답변

주문이 필요하다

NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);

또는 주문이 필요하지 않습니다

NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);


답변

여기에서 mainArray에서 중복 이름 값을 제거하고 결과를 NSMutableArray (listOfUsers)에 저장합니다.

for (int i=0; i<mainArray.count; i++) {
    if (listOfUsers.count==0) {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];

    }
   else if ([[listOfUsers valueForKey:@"name" ] containsObject:[[mainArray objectAtIndex:i] valueForKey:@"name"]])
    {  
       NSLog(@"Same object");
    }
    else
    {
        [listOfUsers addObject:[mainArray objectAtIndex:i]];
    }
}