Najlepszy sposób na usunięcie zduplikowanych wartości ( NSString
) z NSMutableArray
Objective-C?
Czy to najłatwiejszy i właściwy sposób?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Najlepszy sposób na usunięcie zduplikowanych wartości ( NSString
) z NSMutableArray
Objective-C?
Czy to najłatwiejszy i właściwy sposób?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Odpowiedzi:
Twoje NSSet
podejście jest najlepsze, jeśli nie martwisz się o kolejność obiektów, ale z drugiej strony, jeśli nie martwisz się o kolejność, dlaczego nie przechowujesz ich NSSet
na początku?
Napisałem odpowiedź poniżej w 2009 roku; w 2011 roku Apple dodał NSOrderedSet
iOS 5 i Mac OS X 10.7. To, co kiedyś było algorytmem, to teraz dwa wiersze kodu:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
Jeśli martwisz się o kolejność i korzystasz z systemu iOS 4 lub starszego, wykonaj pętlę nad kopią tablicy:
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];
[NSOrderedSet orderedSetWithArray:array];
Możesz następnie odzyskać tablicę przez array = [orderedSet allObjects];
lub po prostu użyj NSOrderedSet
s zamiast NSArray
w pierwszej kolejności.
[orderedSet allObjects]
z [orderedSet array]
!
NSArray
i powinniśmy stworzyć temp NSMutableArray
. W twoim przykładzie pracujesz odwrotnie
NSSet
) lub link @Simon Whitaker zapobiega przed dodaniem zduplikowanej wartości, co jest skutecznym sposobem?
Wiem, że to stare pytanie, ale istnieje bardziej elegancki sposób usuwania duplikatów, NSArray
jeśli nie zależy ci na zamówieniu .
Jeśli użyjemy operatorów obiektów z Key Value Coding, możemy to zrobić:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Jak zauważył również AnthoPak , możliwe jest usuwanie duplikatów na podstawie właściwości. Przykładem może być:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
do usuwania duplikatów według właściwości tablicy obiektów niestandardowych. Na przykład@distinctUnionOfObjects.name
Tak, używanie NSSet jest rozsądnym podejściem.
Aby dodać do odpowiedzi Jima Pulsa, oto alternatywne podejście do usuwania duplikatów przy zachowaniu porządku:
// Initialise a new, empty mutable array
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
Jest to zasadniczo to samo podejście, co Jim's, ale kopiuje unikalne elementy do świeżej, zmiennej tablicy, zamiast usuwać duplikaty z oryginału. To sprawia, że jest nieco bardziej wydajna pamięciowo w przypadku dużej tablicy z dużą ilością duplikatów (nie ma potrzeby wykonywania kopii całej tablicy) i jest moim zdaniem trochę bardziej czytelna.
Zauważ, że w obu przypadkach sprawdzenie, czy element jest już uwzględniony w tablicy docelowej (używając containsObject:
w moim przykładzie lub indexOfObject:inRange:
w Jim's), nie jest dobrze skalowane dla dużych tablic. Te testy są uruchamiane w czasie O (N), co oznacza, że jeśli podwoisz rozmiar oryginalnej tablicy, wykonanie każdego sprawdzenia potrwa dwa razy dłużej. Ponieważ sprawdzasz każdy obiekt w tablicy, będziesz także uruchamiać więcej tych droższych testów. Ogólny algorytm (zarówno mój, jak i Jima) działa w czasie O (N 2 ), co szybko staje się kosztowne, gdy oryginalna tablica rośnie.
Aby sprowadzić to do czasu O (N), możesz użyć a NSMutableSet
do przechowywania rekordu elementów już dodanych do nowej tablicy, ponieważ wyszukiwania NSSet mają wartość O (1) zamiast O (N). Innymi słowy, sprawdzenie, czy element jest członkiem zestawu NSSet, zajmuje tyle samo czasu, niezależnie od tego, ile elementów znajduje się w zestawie.
Kod wykorzystujący to podejście wyglądałby mniej więcej tak:
NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];
for (id obj in originalArray) {
if (![seen containsObject:obj]) {
[unique addObject:obj];
[seen addObject:obj];
}
}
To wciąż wydaje się trochę marnotrawne; nadal generujemy nową tablicę, gdy pytanie jasno wskazywało, że oryginalna tablica jest zmienna, więc powinniśmy być w stanie usunąć ją na miejscu i zaoszczędzić trochę pamięci. Coś takiego:
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++;
}
}
AKTUALIZACJA : Yuri Niyazov wskazał, że moja ostatnia odpowiedź faktycznie działa w czasie O (N 2 ), ponieważ removeObjectAtIndex:
prawdopodobnie działa w czasie O (N).
(Mówi „prawdopodobnie”, ponieważ nie wiemy na pewno, jak to zaimplementowano; ale jedną z możliwych implementacji jest to, że po usunięciu obiektu w indeksie X metoda przechodzi przez każdy element od indeksu X + 1 do ostatniego obiektu w tablicy , przenosząc je do poprzedniego indeksu. Jeśli tak jest, to rzeczywiście jest to wydajność O (N)).
Więc co robić? To zależy od sytuacji. Jeśli masz dużą tablicę i spodziewasz się tylko niewielkiej liczby duplikatów, funkcja de-duplikacji w miejscu będzie działać dobrze i pozwoli zaoszczędzić na tworzeniu zduplikowanej tablicy. Jeśli masz tablicę, w której spodziewasz się wielu duplikatów, prawdopodobnie najlepszym rozwiązaniem jest utworzenie oddzielnej, pozbawionej dupleksu tablicy. Wniosek jest taki, że notacja duże-O opisuje tylko charakterystykę algorytmu, a nie mówi ostatecznie, który jest najlepszy w danych okolicznościach.
Jeśli celujesz w iOS 5+ (który obejmuje cały świat iOS), najlepiej używać NSOrderedSet
. Usuwa duplikaty i zachowuje kolejność plików NSArray
.
Po prostu zrób
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
Możesz teraz przekonwertować go z powrotem na unikalny NSArray
NSArray *uniqueArray = orderedSet.array;
Lub po prostu użyć orderedSet ponieważ ma takie same metody jak NSArray podobnego objectAtIndex:
, firstObject
i tak dalej.
Sprawdzanie członkostwa w usłudze contains
jest jeszcze szybsze NSOrderedSet
niż w przypadku domenyNSArray
Aby uzyskać więcej informacji, zapoznaj się z dokumentacją NSOrderedSet Reference
Potrzebujesz porządku
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
lub nie potrzebujesz zamówienia
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
Tutaj usunąłem zduplikowane wartości nazw z mainArray i zapisz wynik w 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]];
}
}
Zwróć uwagę, że jeśli masz posortowaną tablicę, nie musisz sprawdzać każdego innego elementu w tablicy, tylko ostatni element. Powinno to być znacznie szybsze niż sprawdzanie wszystkich elementów.
// sortedSourceArray is the source array, already sorted
NSMutableArray *newArray = [[NSMutableArray alloc] initWithObjects:[sortedSourceArray objectAtIndex:0]];
for (int i = 1; i < [sortedSourceArray count]; i++)
{
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
{
[newArray addObject:[tempArray objectAtIndex:i]];
}
}
Wygląda na to, że NSOrderedSet
odpowiedzi, które również są sugerowane, wymagają dużo mniej kodu, ale jeśli NSOrderedSet
z jakiegoś powodu nie możesz użyć , a masz posortowaną tablicę, uważam, że moje rozwiązanie byłoby najszybsze. Nie jestem pewien, jak wypada to w porównaniu z szybkością NSOrderedSet
rozwiązań. Zauważ również, że mój kod jest sprawdzany isEqualToString:
, więc ta sama seria liter nie pojawi się więcej niż raz w newArray
. Nie jestem pewien, czy NSOrderedSet
rozwiązania usuwają duplikaty na podstawie wartości lub lokalizacji w pamięci.
Mój przykład zakłada, że sortedSourceArray
zawiera tylko NSString
s, tylko NSMutableString
s lub ich połączenie. Jeśli sortedSourceArray
zamiast tego zawiera tylko NSNumber
s lub tylko NSDate
s, możesz zamienić
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
z
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
i powinno działać idealnie. Jeśli sortedSourceArray
zawiera kombinację NSString
s, NSNumber
s i / lub NSDate
s, prawdopodobnie ulegnie awarii.
Istnieje operator obiektu KVC, który oferuje bardziej eleganckie rozwiązanie. uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Oto kategoria NSArray .
Jeszcze jeden prosty sposób, który możesz wypróbować, który nie doda zduplikowanej wartości przed dodaniem obiektu do tablicy: -
// Załóżmy, że mutableArray jest przydzielona i zainicjowana oraz zawiera pewną wartość
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
Usuń zduplikowane wartości z NSMutableArray w Objective-C
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
Oto kod usuwania zduplikowanych wartości z NSMutable Array. . to będzie działać dla Ciebie. myArray to Twoja Mutable Array, z której chcesz usunąć zduplikowane wartości.
for(int j = 0; j < [myMutableArray count]; j++){
for( k = j+1;k < [myMutableArray count];k++){
NSString *str1 = [myMutableArray objectAtIndex:j];
NSString *str2 = [myMutableArray objectAtIndex:k];
if([str1 isEqualToString:str2])
[myMutableArray removeObjectAtIndex:k];
}
} // Now print your array and will see there is no repeated value
po prostu użyj tego prostego kodu:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
ponieważ nsset nie zezwala na zduplikowane wartości i wszystkie obiekty zwracają tablicę
NSOrderedSet
insteed of NSSet
.