Cara terbaik untuk menghapus nilai duplikat ( NSString
) dari NSMutableArray
di Objective-C?
Apakah ini cara termudah dan tepat untuk melakukannya?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Cara terbaik untuk menghapus nilai duplikat ( NSString
) dari NSMutableArray
di Objective-C?
Apakah ini cara termudah dan tepat untuk melakukannya?
uniquearray = [[NSSet setWithArray:yourarray] allObjects];
Jawaban:
NSSet
Pendekatan Anda adalah yang terbaik jika Anda tidak khawatir tentang urutan objek, tetapi sekali lagi, jika Anda tidak khawatir tentang urutannya, lalu mengapa Anda tidak menyimpannya di NSSet
awal?
Saya menulis jawaban di bawah ini pada tahun 2009; pada tahun 2011, Apple ditambahkan NSOrderedSet
ke iOS 5 dan Mac OS X 10.7. Apa yang tadinya merupakan algoritma sekarang adalah dua baris kode:
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
Jika Anda khawatir tentang pesanan dan Anda menjalankan iOS 4 atau lebih lama, lewati salinan array:
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];
Anda kemudian dapat kembali array melalui array = [orderedSet allObjects];
atau hanya menggunakan NSOrderedSet
s bukan NSArray
di tempat pertama.
[orderedSet allObjects]
dengan [orderedSet array]
!
NSArray
dan harus membuat temp NSMutableArray
. Dalam contoh Anda, Anda bekerja sebaliknya
NSSet
Adakah yang tahu pandangan terbaik untuk menghapus duplikat apakah metode ini (menggunakan ) atau tautan @Simon Whitaker mencegah sebelum menambahkan nilai duplikat yang merupakan cara efisien?
Saya tahu ini adalah pertanyaan lama, tetapi ada cara yang lebih elegan untuk menghapus duplikat di NSArray
jika Anda tidak peduli dengan pesanan .
Jika kita menggunakan Object Operator dari Key Value Coding kita bisa melakukan ini:
uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Sebagai AnthoPak juga mencatat adalah mungkin untuk menghapus duplikat berdasarkan properti. Contohnya adalah:@distinctUnionOfObjects.name
@distinctUnionOfObjects.property
untuk menghapus duplikat berdasarkan properti dari array objek kustom. Misalnya@distinctUnionOfObjects.name
Ya, menggunakan NSSet adalah pendekatan yang masuk akal.
Untuk menambah jawaban Jim Puls, berikut adalah pendekatan alternatif untuk menghapus duplikat sambil mempertahankan pesanan:
// Initialise a new, empty mutable array
NSMutableArray *unique = [NSMutableArray array];
for (id obj in originalArray) {
if (![unique containsObject:obj]) {
[unique addObject:obj];
}
}
Ini pada dasarnya pendekatan yang sama dengan Jim tetapi menyalin item unik ke array yang bisa berubah baru daripada menghapus duplikat dari aslinya. Ini membuatnya sedikit lebih efisien dalam hal array besar dengan banyak duplikat (tidak perlu membuat salinan seluruh array), dan menurut saya sedikit lebih mudah dibaca.
Perhatikan bahwa dalam kedua kasus, memeriksa untuk melihat apakah item sudah termasuk dalam array target (menggunakan containsObject:
dalam contoh saya, atau indexOfObject:inRange:
dalam Jim) tidak skala dengan baik untuk array besar. Pemeriksaan tersebut berjalan dalam waktu O (N), yang berarti bahwa jika Anda menggandakan ukuran array asli maka setiap pemeriksaan akan memakan waktu dua kali lebih lama untuk dijalankan. Karena Anda melakukan pemeriksaan untuk setiap objek dalam array, Anda juga akan menjalankan lebih banyak dari pemeriksaan yang lebih mahal itu. Algoritma keseluruhan (baik milik saya maupun Jim) berjalan dalam waktu O (N 2 ), yang menjadi cepat mahal seiring dengan tumbuhnya array asli.
Untuk menurunkannya ke waktu O (N), Anda bisa menggunakan a NSMutableSet
untuk menyimpan catatan item yang sudah ditambahkan ke array baru, karena pencarian NSSet adalah O (1) daripada O (N). Dengan kata lain, memeriksa untuk melihat apakah suatu elemen adalah anggota NSSet membutuhkan waktu yang sama terlepas dari berapa banyak elemen dalam set.
Kode yang menggunakan pendekatan ini akan terlihat seperti ini:
NSMutableArray *unique = [NSMutableArray array];
NSMutableSet *seen = [NSMutableSet set];
for (id obj in originalArray) {
if (![seen containsObject:obj]) {
[unique addObject:obj];
[seen addObject:obj];
}
}
Ini tampaknya masih sedikit boros; kami masih membuat array baru ketika pertanyaan menjelaskan bahwa array asli bisa berubah, jadi kita harus dapat menghapusnya di tempat dan menghemat memori. Sesuatu seperti ini:
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 menunjukkan bahwa jawaban terakhir saya benar-benar berjalan di O (N 2 ) karena removeObjectAtIndex:
mungkin berjalan dalam waktu O (N).
(Dia mengatakan "mungkin" karena kita tidak tahu pasti bagaimana itu diterapkan; tetapi satu kemungkinan implementasi adalah bahwa setelah menghapus objek pada indeks X metode kemudian loop melalui setiap elemen dari indeks X + 1 ke objek terakhir dalam array , memindahkan mereka ke indeks sebelumnya. Jika itu masalahnya maka itu memang kinerja O (N).)
Jadi, apa yang harus dilakukan? Itu tergantung situasi. Jika Anda memiliki array besar dan Anda hanya mengharapkan sejumlah kecil duplikat maka de-duplikasi di tempat akan bekerja dengan baik dan menghemat Anda harus membangun array duplikat. Jika Anda memiliki array di mana Anda mengharapkan banyak duplikat kemudian membangun array terpisah, de-duped mungkin merupakan pendekatan terbaik. Yang dibawa pulang di sini adalah bahwa notasi-O besar hanya menggambarkan karakteristik suatu algoritma, itu tidak akan memberi tahu Anda secara definitif mana yang terbaik untuk keadaan apa pun.
Jika Anda menargetkan iOS 5+ (yang mencakup seluruh dunia iOS), gunakan yang terbaik NSOrderedSet
. Ini menghapus duplikat dan mempertahankan urutan NSArray
.
Kerjakan saja
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourArray];
Anda sekarang dapat mengubahnya kembali ke NSArray unik
NSArray *uniqueArray = orderedSet.array;
Atau cukup gunakan orderedetet karena memiliki metode yang sama seperti NSArray objectAtIndex:
, firstObject
dan sebagainya.
Pemeriksaan keanggotaan dengan contains
bahkan lebih cepat NSOrderedSet
daripada padaNSArray
Untuk checkout lebih lanjut, Referensi NSOrderedSet
Tersedia dalam OS X v10.7 dan yang lebih baru.
Jika Anda khawatir tentang pesanan, cara yang benar untuk dilakukan
NSArray *no = [[NSOrderedSet orderedSetWithArray:originalArray]allObjects];
Berikut adalah kode untuk menghapus nilai duplikat dari NSArray dalam Pesanan.
butuh pesanan
NSArray *yourarray = @[@"a",@"b",@"c"];
NSOrderedSet *orderedSet = [NSOrderedSet orderedSetWithArray:yourarray];
NSArray *arrayWithoutDuplicates = [orderedSet array];
NSLog(@"%@",arrayWithoutDuplicates);
atau tidak perlu dipesan
NSSet *set = [NSSet setWithArray:yourarray];
NSArray *arrayWithoutOrder = [set allObjects];
NSLog(@"%@",arrayWithoutOrder);
Di sini saya menghapus nilai nama duplikat dari mainArray dan menyimpan hasil di 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]];
}
}
Perhatikan bahwa jika Anda memiliki array yang diurutkan, Anda tidak perlu memeriksa setiap item dalam array, hanya item terakhir. Ini harus jauh lebih cepat daripada memeriksa semua item.
// 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]];
}
}
Sepertinya NSOrderedSet
jawaban yang juga disarankan memerlukan kode jauh lebih sedikit, tetapi jika Anda tidak dapat menggunakan NSOrderedSet
karena suatu alasan, dan Anda memiliki array yang diurutkan, saya percaya solusi saya akan menjadi yang tercepat. Saya tidak yakin bagaimana membandingkannya dengan kecepatan NSOrderedSet
solusi. Perhatikan juga bahwa kode saya sedang diperiksa isEqualToString:
, sehingga seri huruf yang sama tidak akan muncul lebih dari satu kali newArray
. Saya tidak yakin apakah NSOrderedSet
solusi akan menghapus duplikat berdasarkan nilai atau berdasarkan lokasi memori.
Contoh saya anggap sortedSourceArray
berisi hanya NSString
s, hanya NSMutableString
s, atau campuran keduanya. Jika sortedSourceArray
sebaliknya hanya berisi NSNumber
s atau hanya NSDate
s, Anda dapat mengganti
if (![[sortedSourceArray objectAtIndex:i] isEqualToString:[sortedSourceArray objectAtIndex:(i-1)]])
dengan
if ([[sortedSourceArray objectAtIndex:i] compare:[sortedSourceArray objectAtIndex:(i-1)]] != NSOrderedSame)
dan itu harus bekerja dengan sempurna. Jika sortedSourceArray
berisi campuran NSString
s, NSNumber
s, dan / atau NSDate
s, itu mungkin akan macet.
Ada Operator Objek KVC yang menawarkan solusi yang lebih elegan. uniquearray = [yourarray valueForKeyPath:@"@distinctUnionOfObjects.self"];
Ini adalah kategori NSArray .
Satu lagi cara sederhana yang dapat Anda coba yang tidak akan menambah Nilai rangkap sebelum menambahkan objek dalam array: -
// Asumsikan mutableArray dialokasikan dan diinisialisasi dan berisi beberapa nilai
if (![yourMutableArray containsObject:someValue])
{
[yourMutableArray addObject:someValue];
}
Hapus nilai duplikat dari NSMutableArray di Objective-C
NSMutableArray *datelistArray = [[NSMutableArray alloc]init];
for (Student * data in fetchStudentDateArray)
{
if([datelistArray indexOfObject:data.date] == NSNotFound)
[datelistArray addObject:data.date];
}
Berikut adalah kode untuk menghapus nilai duplikat dari NSMutable Array. .itu akan bekerja untuk Anda. myArray adalah Array Mutable Anda yang ingin Anda hapus nilai duplikat ..
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
cukup gunakan kode sederhana ini:
NSArray *hasDuplicates = /* (...) */;
NSArray *noDuplicates = [[NSSet setWithArray: hasDuplicates] allObjects];
karena nsset tidak mengizinkan nilai duplikat dan semua objek mengembalikan array
NSOrderedSet
insteed of NSSet
.