Objective-C yinelenen değerleri ( NSString
) kaldırmak için en iyi yolu NSMutableArray
?
Bunu yapmanın en kolay ve doğru yolu mu?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Objective-C yinelenen değerleri ( NSString
) kaldırmak için en iyi yolu NSMutableArray
?
Bunu yapmanın en kolay ve doğru yolu mu?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Yanıtlar:
Kişisel NSSet
sonra tekrar nesnelerin sırasına hakkında endişeli, ama değilseniz sırayla endişe değilseniz yaklaşım o zaman neden onları saklamak değil, en iyisi NSSet
ile başlamalı?
Aşağıdaki cevabı 2009'da yazdım; 2011'de Apple NSOrderedSet
, iOS 5 ve Mac OS X 10.7'ye eklendi. Bir algoritma olan şey şimdi iki kod satırıdır:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
Siparişle ilgili endişeleriniz varsa ve iOS 4 veya daha eski bir sürümde çalışıyorsanız, dizinin bir kopyasının üzerine gelin:
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];
Bir diziyi geri alabilir array = [orderedSet allObjects];
veya ilk etapta NSOrderedSet
s yerine kullanabilirsiniz NSArray
.
[orderedSet allObjects]
ile [orderedSet array]
!
NSArray
temp oluşturduk ve yaratmalıyız NSMutableArray
.
NSSet
) veya @Simon Whitaker bağlantı verimli yolu olan yinelenen değer eklemeden önce önlemek mi?
Bunun eski bir soru olduğunu biliyorum, ancak NSArray
siparişi umursamıyorsanız kopyaları kaldırmanın daha zarif bir yolu var .
Anahtar Değer Kodlamasından Nesne İşleçleri kullanırsak bunu yapabiliriz:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
As AnthoPak da belirtildiği bir özelliğine dayanarak çiftleri kaldırmak mümkündür. Örnek olarak şunlar verilebilir:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
Bir dizi özel nesnenin özelliğine göre yinelenenleri kaldırmak gibi de kullanılabileceğini unutmayın . Örneğin@distinctUnionOfObjects.name
Evet, NSSet kullanmak mantıklı bir yaklaşımdır.
Jim Puls'un cevabına eklemek için, sırayı korurken kopyaları çıkarmaya alternatif bir yaklaşım var:
// Initialise a new, empty mutable array
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
Aslında Jim'inkiyle aynı yaklaşımdır, ancak orijinali kopyaları silmek yerine benzersiz öğeleri yeni bir değişken diziye kopyalar. Bu, çoğaltılmış çok sayıda (tüm dizinin bir kopyasını oluşturmaya gerek yok) büyük bir dizi durumunda biraz daha bellek verimli hale getirir ve bence biraz daha okunabilir.
Her iki durumda da, bir öğenin hedef diziye zaten dahil edilip edilmediğini kontrol etmenin ( örneğimde containsObject:
veya indexOfObject:inRange:
Jim'inde) büyük diziler için iyi ölçeklenmediğini unutmayın. Bu kontroller O (N) zamanında çalışır, yani orijinal dizinin boyutunu iki katına çıkarırsanız, her kontrolün çalışması iki kat daha uzun sürer. Dizideki her bir nesne için denetim yaptığınızdan, bu daha pahalı denetimlerin çoğunu da çalıştırırsınız. Genel algoritma (hem benim hem de Jim'in) O (N 2 ) zamanında çalışır ve orijinal dizi büyüdükçe hızlı bir şekilde pahalı olur.
Bunu O (N) zamanına düşürmek için NSMutableSet
, yeni diziye zaten eklenmiş olan öğelerin kaydını saklamak için a kullanabilirsiniz , çünkü NSSet aramaları O (N) yerine O (1) şeklindedir. Başka bir deyişle, bir öğenin bir NSSet'in üyesi olup olmadığını kontrol etmek, kümede kaç öğe bulunduğundan bağımsız olarak aynı zamanı alır.
Bu yaklaşımı kullanan kod şöyle görünecektir:
NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];
for (id obj in originalArray) {
if (![seen containsObject:obj]) {
[unique addObject:obj];
[seen addObject:obj];
}
}
Bu yine de biraz savurgan görünüyor; orijinal dizinin değiştirilebilir olduğunu açıkça belirttikten sonra hala yeni bir dizi oluşturuyoruz, bu yüzden yerinde de-dupe ve biraz bellek tasarrufu yapabilmeliyiz. Bunun gibi bir şey:
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++;
}
}
GÜNCELLEME : Yuri Niyazov , son cevabımın aslında O (N 2 ) 'de, çünkü muhtemelen O (N) zamanda çalıştığına dikkat çekti .removeObjectAtIndex:
("Muhtemelen" diyor çünkü nasıl uygulandığından emin değiliz; ancak olası bir uygulama, X dizinindeki nesneyi sildikten sonra yöntemin X + 1 dizininden dizideki son nesneye kadar her öğeye geçiş yapmasıdır. bunları bir önceki dizine taşıyın. Durum buysa, aslında O (N) performansıdır.)
Peki ne yapmalı? Bu duruma bağlıdır. Büyük bir diziniz varsa ve yalnızca az sayıda kopya bekliyorsanız, yerinde çoğaltma işlemi iyi çalışır ve yinelenen bir dizi oluşturmak zorunda kalmanızı sağlar. Eğer çok sayıda kopya beklediğiniz bir dizi varsa, o zaman ayrı, de-duped dizi oluşturmak muhtemelen en iyi yaklaşımdır. Buradaki devralma, big-O gösteriminin sadece bir algoritmanın özelliklerini tanımlamasıdır, size herhangi bir koşul için en iyisi olduğunu kesin olarak söylemez.
İOS 5+ 'ı (tüm iOS dünyasını kapsayan şey) hedefliyorsanız, en iyi şekilde kullanın NSOrderedSet
. Yinelemeleri kaldırır ve sırasını korur NSArray
.
Sadece yap
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
Şimdi tekrar benzersiz bir NSArray'e dönüştürebilirsiniz
NSArray *uniqueArray = orderedSet.array;
Bunun gibi bir NSArray gibi aynı yöntemleri vardır çünkü Ya da sadece orderedSet kullanmak objectAtIndex:
, firstObject
vb vb.
A üyelik onay contains
daha hızlı olduğunu NSOrderedSet
bir olurdu dahaNSArray
Daha fazla ödeme için NSOrderedSet Başvurusu
OS Xv10.7 ve sonraki sürümlerinde kullanılabilir.
Sipariş hakkında endişeleniyorsanız, doğru yol
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];
Sıralı olarak NSArray'den yinelenen değerleri kaldırmanın kodu.
sipariş gerekli
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
veya siparişe gerek yok
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
Burada mainArray ve mağaza sonucu NSMutableArray (listOfUsers) yinelenen ad değerlerini kaldırdım
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]];
}
}
Sıralanmış bir diziniz varsa, dizideki diğer tüm öğeleri, yalnızca son öğeyi kontrol etmeniz gerekmediğini unutmayın. Bu, tüm öğelere karşı kontrol etmekten çok daha hızlı olmalıdır.
// 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]];
}
}
NSOrderedSet
Ayrıca önerilen cevaplar çok daha az kod gerektirir gibi görünüyor , ama bir NSOrderedSet
nedenle kullanamazsanız ve sıralı bir dizi varsa, benim çözüm en hızlı olacağını düşünüyorum. NSOrderedSet
Çözümlerin hızı ile nasıl karşılaştırıldığından emin değilim . Kodumun kontrol ettiğini de unutmayın isEqualToString:
, bu nedenle aynı harf dizisi birden fazla kez görünmeyecektir newArray
. NSOrderedSet
Çözümlerin, değere veya bellek konumuna göre yinelenenleri kaldıracağından emin değilim .
Örneğim sortedSourceArray
sadece NSString
s, sadece NSMutableString
s veya ikisinin bir karışımını içerdiğini varsayar . Eğer sortedSourceArray
yerine içeriyor sadece NSNumber
s ya da sadece NSDate
, biliyor yerine
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
ile
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
ve mükemmel çalışmalıdır. Eğer sortedSourceArray
bir karışımını içerir NSString
ler, NSNumber
lar, ve / veya NSDate
s, muhtemelen çökmesine.
Daha zarif bir çözüm sunan bir KVC Nesne Operatörü var uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
İşte bir NSArray kategorisi .
Diziye nesne eklemeden önce yinelenen Değer eklemeyeceğinizi deneyebileceğiniz daha basit bir yol: -
// mutableArray öğesinin ayrıldığını ve başlattığını ve bir değer içerdiğini varsayın
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
Objective-C NSMutableArray yinelenen değerleri kaldırma
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
NSMutable Array öğesinden yinelenen değerleri kaldırmanın kodu. sizin için çalışacaktır. myArray, yinelenen değerleri kaldırmak istediğiniz Değişken Dizinizdir.
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
sadece bu basit kodu kullanın:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
nsset yinelenen değerlere izin vermediğinden ve tüm nesneler bir dizi döndürdüğü için
NSOrderedSet
insteed kullanın NSSet
.