Der beste Weg, um doppelte Werte ( NSString
) aus NSMutableArray
Objective-C zu entfernen ?
Ist dies der einfachste und richtige Weg?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Der beste Weg, um doppelte Werte ( NSString
) aus NSMutableArray
Objective-C zu entfernen ?
Ist dies der einfachste und richtige Weg?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Antworten:
Ihr NSSet
Ansatz ist der beste, wenn Sie sich keine Sorgen um die Reihenfolge der Objekte machen. Wenn Sie sich jedoch keine Sorgen um die Reihenfolge machen, warum speichern Sie sie dann nicht zunächst in einer NSSet
?
Ich habe die Antwort unten 2009 geschrieben. Im Jahr 2011 fügte Apple NSOrderedSet
iOS 5 und Mac OS X 10.7 hinzu. Was früher ein Algorithmus war, besteht jetzt aus zwei Codezeilen:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
Wenn Sie sich über die Reihenfolge Sorgen machen und iOS 4 oder früher verwenden, durchlaufen Sie eine Kopie des Arrays:
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];
Sie einfach. Sie können dann ein Array über zurückholen array = [orderedSet allObjects];
oder einfach NSOrderedSet
s anstelle von s verwenden NSArray
.
[orderedSet allObjects]
mit [orderedSet array]
!
NSArray
und sollten normalerweise Temp schaffen NSMutableArray
. In Ihrem Beispiel arbeiten Sie umgekehrt
NSSet
Weiß jemand, welche Ansicht am besten geeignet ist, um Duplikate zu entfernen ? Ist diese Methode (mit ) oder der @ Simon Whitaker- Link zu verhindern, bevor Duplikate hinzugefügt werden?
Ich weiß, dass dies eine alte Frage ist, aber es gibt eine elegantere Möglichkeit, Duplikate in einem zu entfernen, NSArray
wenn Sie sich nicht für die Reihenfolge interessieren .
Wenn wir Objektoperatoren aus der Schlüsselwertcodierung verwenden , können wir dies tun:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Wie AnthoPak ebenfalls feststellte, ist es möglich, Duplikate basierend auf einer Eigenschaft zu entfernen. Ein Beispiel wäre:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
, um Duplikate nach Eigenschaften eines Arrays benutzerdefinierter Objekte zu entfernen. Zum Beispiel@distinctUnionOfObjects.name
Ja, die Verwendung von NSSet ist ein sinnvoller Ansatz.
Um die Antwort von Jim Puls zu ergänzen, gibt es hier einen alternativen Ansatz zum Entfernen von Duplikaten unter Beibehaltung der Reihenfolge:
// Initialise a new, empty mutable array
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
Es ist im Wesentlichen der gleiche Ansatz wie bei Jim, kopiert jedoch eindeutige Elemente in ein neues veränderbares Array, anstatt Duplikate aus dem Original zu löschen. Dies macht es etwas speichereffizienter bei einem großen Array mit vielen Duplikaten (es ist nicht erforderlich, eine Kopie des gesamten Arrays zu erstellen) und ist meiner Meinung nach etwas lesbarer.
Beachten Sie, dass in beiden Fällen die Überprüfung, ob ein Element bereits im Zielarray enthalten ist ( containsObject:
in meinem Beispiel oder indexOfObject:inRange:
in Jims), für große Arrays nicht gut skalierbar ist. Diese Überprüfungen werden in O (N) -Zeit ausgeführt. Wenn Sie also die Größe des ursprünglichen Arrays verdoppeln, dauert die Ausführung jeder Überprüfung doppelt so lange. Da Sie die Prüfung für jedes Objekt im Array durchführen, führen Sie auch mehr dieser teureren Prüfungen durch. Der Gesamtalgorithmus (sowohl meiner als auch Jims) läuft in O (N 2 ) -Zeit, was schnell teuer wird, wenn das ursprüngliche Array wächst.
Um dies auf O (N) Zeit zu NSMutableSet
reduzieren, können Sie mit a einen Datensatz von Elementen speichern, die bereits zum neuen Array hinzugefügt wurden, da NSSet-Lookups O (1) und nicht O (N) sind. Mit anderen Worten, die Überprüfung, ob ein Element Mitglied eines NSSet ist, dauert unabhängig von der Anzahl der Elemente in der Gruppe dieselbe Zeit.
Code, der diesen Ansatz verwendet, würde ungefähr so aussehen:
NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];
for (id obj in originalArray) {
if (![seen containsObject:obj]) {
[unique addObject:obj];
[seen addObject:obj];
}
}
Dies scheint jedoch immer noch ein wenig verschwenderisch; Wir generieren immer noch ein neues Array, wenn die Frage klarstellt, dass das ursprüngliche Array veränderbar ist. Daher sollten wir in der Lage sein, es zu entfernen und Speicherplatz zu sparen. Etwas wie das:
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++;
}
}
UPDATE : Yuri Niyazov wies darauf hin, dass meine letzte Antwort tatsächlich in O (N 2 ) removeObjectAtIndex:
läuft, weil sie wahrscheinlich in O (N) läuft.
(Er sagt "wahrscheinlich", weil wir nicht genau wissen, wie es implementiert ist. Eine mögliche Implementierung ist jedoch, dass die Methode nach dem Löschen des Objekts am Index X jedes Element vom Index X + 1 bis zum letzten Objekt im Array durchläuft Wenn dies der Fall ist, ist dies tatsächlich die O (N) -Leistung.)
Also, was tun? Es hängt von der Situation ab. Wenn Sie ein großes Array haben und nur eine kleine Anzahl von Duplikaten erwarten, funktioniert die direkte Deduplizierung einwandfrei und Sie müssen kein doppeltes Array erstellen. Wenn Sie ein Array haben, in dem Sie viele Duplikate erwarten, ist der Aufbau eines separaten, nicht duplizierten Arrays wahrscheinlich der beste Ansatz. Das Mitnehmen hier ist, dass die Big-O-Notation nur die Eigenschaften eines Algorithmus beschreibt und Ihnen nicht definitiv sagt, welche für einen bestimmten Umstand am besten ist.
Wenn Sie auf iOS 5+ abzielen (was die gesamte iOS-Welt abdeckt), verwenden Sie es am besten NSOrderedSet
. Es entfernt Duplikate und behält die Reihenfolge Ihrer NSArray
.
Mach einfach
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
Sie können es jetzt wieder in ein eindeutiges NSArray konvertieren
NSArray *uniqueArray = orderedSet.array;
Oder verwenden Sie einfach das orderSet, da es die gleichen Methoden wie ein NSArray objectAtIndex:
hat firstObject
und so weiter.
Ein Mitgliedschafts-Check mit contains
ist auf dem noch schneller NSOrderedSet
als auf einemNSArray
Weitere Informationen finden Sie in der NSOrderedSet-Referenz
Verfügbar in OS X 10.7 und höher.
Wenn Sie sich Sorgen um die Bestellung machen, ist dies der richtige Weg
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];
Hier ist der Code zum Entfernen doppelter Werte aus NSArray in der Reihenfolge.
brauche Bestellung
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
oder brauche keine Bestellung
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
Hier habe ich doppelte Namenswerte aus mainArray entfernt und das Ergebnis in NSMutableArray (listOfUsers) gespeichert.
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]];
}
}
Beachten Sie, dass Sie bei einem sortierten Array nicht mit jedem anderen Element im Array vergleichen müssen, sondern nur mit dem letzten Element. Dies sollte viel schneller sein als die Überprüfung aller Elemente.
// 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]];
}
}
Es sieht so aus, als ob die NSOrderedSet
Antworten, die ebenfalls vorgeschlagen werden, viel weniger Code erfordern. Wenn Sie jedoch NSOrderedSet
aus irgendeinem Grund keinen verwenden können und ein sortiertes Array haben, ist meine Lösung meiner Meinung nach die schnellste. Ich bin mir nicht sicher, wie es mit der Geschwindigkeit der NSOrderedSet
Lösungen verglichen wird. Beachten Sie auch, dass mein Code mit überprüft isEqualToString:
, sodass dieselbe Buchstabenfolge nicht mehr als einmal in angezeigt wird newArray
. Ich bin nicht sicher, ob die NSOrderedSet
Lösungen Duplikate basierend auf dem Wert oder basierend auf dem Speicherort entfernen.
In meinem Beispiel wird davon sortedSourceArray
ausgegangen, dass nur NSString
s, nur NSMutableString
s oder eine Mischung aus beiden enthalten ist. Wenn sortedSourceArray
stattdessen nur NSNumber
s oder nur NSDate
s enthält, können Sie ersetzen
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
mit
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
und es sollte perfekt funktionieren. Wenn es sortedSourceArray
eine Mischung aus NSString
s, NSNumber
s und / oder NSDate
s enthält, wird es wahrscheinlich abstürzen.
Es gibt einen KVC- Objektoperator , der eine elegantere Lösung bietet. uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Hier ist eine NSArray-Kategorie .
Eine weitere einfache Möglichkeit, die Sie ausprobieren können, um vor dem Hinzufügen eines Objekts zum Array keinen doppelten Wert hinzuzufügen: -
// Angenommen, mutableArray wird zugewiesen und initialisiert und enthält einen Wert
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
Entfernen Sie doppelte Werte aus NSMutableArray in Objective-C
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
Hier ist der Code zum Entfernen doppelter Werte aus dem NSMutable Array. .es wird für Sie arbeiten. myArray ist Ihr veränderbares Array, mit dem Sie doppelte Werte entfernen möchten.
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
Verwenden Sie einfach diesen einfachen Code:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
da nsset keine doppelten Werte zulässt und alle Objekte ein Array zurückgeben
NSOrderedSet
insteed von NSSet
.