Menghapus elemen duplikat dari array di Swift

252

Saat ini di Swift Anda cukup mengetik Set( yourArray )untuk membuat array unik. (Atau set memerintahkan jika diperlukan.)

Sebelum itu mungkin, bagaimana hal itu dilakukan?


Saya mungkin memiliki array yang terlihat seperti berikut:

[1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

Atau, sungguh, setiap urutan bagian data yang diketik seperti. Yang ingin saya lakukan adalah memastikan bahwa hanya ada satu dari setiap elemen yang identik. Misalnya, array di atas akan menjadi:

[1, 4, 2, 6, 24, 15, 60]

Perhatikan bahwa duplikat 2, 6, dan 15 telah dihapus untuk memastikan bahwa hanya ada satu dari setiap elemen yang identik. Apakah Swift menyediakan cara untuk melakukan ini dengan mudah, atau apakah saya harus melakukannya sendiri?

Altair357
sumber
11
Cara termudah adalah dengan mengkonversi array dalam NSSet, NSSet adalah kumpulan objek yang tidak terurut, jika perlu menjaga ketertiban NSOrderedSet.
Andrea
Anda bisa menggunakan fungsi persimpangan seperti yang Anda temukan di kelas ini dengan fungsi untuk array: github.com/pNre/ExSwift/blob/master/ExSwift/Array.swift
Edwin Vermeer
Bukan bagian dari Swift tetapi saya menggunakan Dollar. $.uniq(array) github.com/ankurp/Dollar#uniq---uniq
Andy
Mungkin jawaban yang paling elegan, paling cerdas dan tercepat disediakan oleh jawaban mxcl di bawah ini. Yang juga membantu menjaga ketertiban
Sayang
1
Kenapa tidak Anda gunakan saja Setdari Swift? Anda dapat memberikan daftar elemen yang tidak diurut dan unik.
TibiaZ

Jawaban:

133

Anda dapat menggulung sendiri, misalnya seperti ini ( diperbarui untuk Swift 1.2 dengan Set ):

func uniq<S : SequenceType, T : Hashable where S.Generator.Element == T>(source: S) -> [T] {
    var buffer = [T]()
    var added = Set<T>()
    for elem in source {
        if !added.contains(elem) {
            buffer.append(elem)
            added.insert(elem)
        }
    }
    return buffer
}

let vals = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let uniqueVals = uniq(vals) // [1, 4, 2, 6, 24, 15, 60]

Versi Swift 3:

func uniq<S : Sequence, T : Hashable>(source: S) -> [T] where S.Iterator.Element == T {
    var buffer = [T]()
    var added = Set<T>()
    for elem in source {
        if !added.contains(elem) {
            buffer.append(elem)
            added.insert(elem)
        }
    }
    return buffer
}

Dan sebagai perpanjangan untuk Array:

extension Array where Element: Hashable {
    var uniques: Array {
        var buffer = Array()
        var added = Set<Element>()
        for elem in self {
            if !added.contains(elem) {
                buffer.append(elem)
                added.insert(elem)
            }
        }
        return buffer
    }
}
Jean-Philippe Pellet
sumber
12
Anda juga bisa mengimplementasikan tubuh fungsi itu sebagaivar addedDict = [T:Bool](); return filter(source) { addedDict(true, forKey: $0) == nil }
Airspeed Velocity
1
@AirspeedVelocity: Maksud Anda updateValue(true, forKey: $0)...alih-alihaddedDict(true, forKey: $0)...
Jawwad
1
Ups ya maaf saya tidak sengaja metode ini! Seharusnya return filter(source) { addedDict.updateValue(true, forKey: $0) == nil }seperti yang Anda katakan.
Airspeed Velocity
21
Hanya kata hati-hati: Hindari membahas kinerja untuk fungsi sederhana seperti ini sampai Anda terbukti bergantung pada kinerja mereka, pada titik mana satu-satunya hal yang harus Anda lakukan adalah tolok ukur. Terlalu sering saya melihat kode yang tidak dapat dipelihara atau bahkan lebih sedikit kode performan karena membuat asumsi. :) Juga, ini mungkin lebih mudah untuk dipahami:let uniques = Array(Set(vals))
Blixt
11
@Blixt Setuju. Sekali lagi, di sini keuntungannya terletak pada menghormati urutan elemen dari array asli.
Jean-Philippe Pellet
493

Anda dapat mengonversi ke set dan kembali ke array dengan mudah:

let unique = Array(Set(originals))

Ini tidak dijamin untuk mempertahankan urutan asli array.

Ben Packard
sumber
37
Apakah ada cara untuk menggunakan set sambil mempertahankan urutan asli array?
Crashalot
6
@ Crashalot Lihat jawaban saya.
Jean-Philippe Pellet
5
Jika Anda perlu menjaga objek tetap unik dengan properti tertentu, daripada juga mengimplementasikan protokol Hashable dan Equatable pada kelas itu, alih-alih hanya menggunakan transformasi Array-> Set-> Array
Fawkes
2
Bagus!! Apa kompleksitas waktu dari solusi ini?
JW.ZG
2
Gagal jika elemen dalam originalsbukan Hashable; hanya Hashabletipe data yang dapat ditambahkan ke Set, namun tipe data apa pun dapat ditambahkan ke array.
Mecki
69

Banyak jawaban tersedia di sini, tetapi saya melewatkan ekstensi sederhana ini, cocok untuk Swift 2 dan lebih tinggi:

extension Array where Element:Equatable {
    func removeDuplicates() -> [Element] {
        var result = [Element]()

        for value in self {
            if result.contains(value) == false {
                result.append(value)
            }
        }

        return result
    }
}

Jadikan super sederhana. Dapat disebut seperti ini:

let arrayOfInts = [2, 2, 4, 4]
print(arrayOfInts.removeDuplicates()) // Prints: [2, 4]

Penyaringan berdasarkan properti

Untuk memfilter array berdasarkan properti, Anda dapat menggunakan metode ini:

extension Array {

    func filterDuplicates(@noescape includeElement: (lhs:Element, rhs:Element) -> Bool) -> [Element]{
        var results = [Element]()

        forEach { (element) in
            let existingElements = results.filter {
                return includeElement(lhs: element, rhs: $0)
            }
            if existingElements.count == 0 {
                results.append(element)
            }
        }

        return results
    }
}

Yang dapat Anda hubungi sebagai berikut:

let filteredElements = myElements.filterDuplicates { $0.PropertyOne == $1.PropertyOne && $0.PropertyTwo == $1.PropertyTwo }
Antoine
sumber
@Antoine Terima kasih atas Pemfilteran berdasarkan ekstensi properti. Ini sangat berguna. Tapi bisakah Anda jelaskan cara kerjanya. Ini terlalu sulit untuk dipahami bagi saya. Terima kasih
Mostafa Mohamed Raafat
Pembaruan untuk swift 3: func filterDuplicates (_ includeElement: (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] {
cbartel
Bagian pertama dari jawaban ini ( extension Array where Element: Equatable) sedang digantikan oleh stackoverflow.com/a/36048862/1033581 yang menawarkan solusi yang lebih kuat ( extension Sequence where Iterator.Element: Equatable).
Cœur
7
Ini akan memiliki O(n²)kinerja waktu, yang sangat buruk untuk array besar.
Duncan C
Anda harus menggunakan satu set untuk melacak elemen yang terlihat sejauh ini, untuk membawa O(n²)kompleksitas yang mengerikan ini kembali keO(n)
Alexander - Reinstate Monica
63

Swift 3.0

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))
Jovan Stankovic
sumber
1
biarkan uniqueOrderedNames = Array (NSOrderedSet (array: userNames)) sebagai! [String] jika Anda memiliki array String, bukan dari Any
Zaporozhchenko Oleksandr
Gagal jika elemen dalam arraybukan Hashable; hanya Hashabletipe data yang dapat ditambahkan ke Set, namun tipe data apa pun dapat ditambahkan ke array.
Mecki
Diuji dalam Swift 5.1b5, mengingat bahwa elemen-elemennya Hashable dan keinginan untuk mempertahankan pemesanan, NSOrderedSet (array: array) .array sedikit lebih cepat daripada fungsi swift murni yang unik () menggunakan set dengan filter. Saya menguji dengan 5100 string yang menghasilkan 13 nilai unik.
dlemex
62

Jika Anda memasukkan kedua ekstensi dalam kode Anda, Hashableversi yang lebih cepat akan digunakan bila memungkinkan, dan Equatableversi tersebut akan digunakan sebagai cadangan.

public extension Sequence where Element: Hashable {
  var firstUniqueElements: [Element] {
    var set: Set<Element> = []
    return filter { set.insert($0).inserted }
  }
}

public extension Sequence where Element: Equatable {
  var firstUniqueElements: [Element] {
    reduce(into: []) { uniqueElements, element in
      if !uniqueElements.contains(element) {
        uniqueElements.append(element)
      }
    }
  }
}

Jika pesanan tidak penting, maka Anda selalu dapat menggunakan Set initializer ini .

Jessy
sumber
OK saya mengerti. saya tidak dapat menyebutnya karena array saya adalah array struct ... bagaimana saya akan menanganinya dalam kasus saya? struct dari 20 variabel yang berbeda, string dan [string]
David Seek
@David Seek Sepertinya Anda belum membuat hashable atau equatable Anda yang ketat. Apakah itu benar?
Jessy
1
@ DavidSeek menyukai ini, uniqueArray = nonUniqueArray.uniqueElements
Mert Celik
ya jangan khawatir. berhasil setelah itu. sudah hampir 2 tahun sekarang: P
David Seek
Ini akan memiliki O(n²)kinerja waktu, yang sangat buruk untuk array besar.
Duncan C
44

edit / perbarui Swift 4 atau lebih baru

Kami juga dapat memperluas RangeReplaceableCollectionprotokol untuk memungkinkannya digunakan dengan StringProtocoltipe juga:

extension RangeReplaceableCollection where Element: Hashable {
    var orderedSet: Self {
        var set = Set<Element>()
        return filter { set.insert($0).inserted }
    }
    mutating func removeDuplicates() {
        var set = Set<Element>()
        removeAll { !set.insert($0).inserted }
    }
}

let integers = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let integersOrderedSet = integers.orderedSet // [1, 4, 2, 6, 24, 15, 60]

"abcdefabcghi".orderedSet  // "abcdefghi"
"abcdefabcghi".dropFirst(3).orderedSet // "defabcghi"

Metode bermutasi:

var string = "abcdefabcghi"
string.removeDuplicates() 
string  //  "abcdefghi"

var substring = "abcdefabcdefghi".dropFirst(3)  // "defabcdefghi"
substring.removeDuplicates()
substring   // "defabcghi"

Untuk Swift 3 klik di sini

Leo Dabus
sumber
1
Saya suka ini, ia bekerja dengan berbagai kamus juga!
DeyaEldeen
6
O (N ^ 2) buruk :(
Alexander - Reinstate Monica
1
@Alexander Leo Dabus telah menggantikan reduceimplementasinya, jadi sekarang kompleksitasnya berbeda.
Cœur
1
Hasilnya menarik. Untuk 1 juta item unik dan 8 juta, versi filter lebih cepat. Namun, versi berbasis-filter membutuhkan waktu 8,38 x lebih lama untuk 8 juta item unik (sedikit O(n)demi sedikit), di mana versi berbasis-flat membutuhkan waktu 7,47x lebih lama untuk 8 juta entri unik dari 1 juta, menunjukkan bahwa versi berbasis-flatmap memiliki skala yang lebih baik . Entah bagaimana versi berbasis flatmap sedikit lebih baik daripada O(n)waktu!
Duncan C
1
Bahkan, ketika saya menjalankan tes dengan 64x lebih banyak item dalam array, versi berbasis flatmap lebih cepat.
Duncan C
43

Cepat 4

public extension Array where Element: Hashable {
    func uniqued() -> [Element] {
        var seen = Set<Element>()
        return filter{ seen.insert($0).inserted }
    }
}

setiap usaha untuk insertjuga akan kembali tupel: (inserted: Bool, memberAfterInsert: Set.Element). Lihat dokumentasi .

Menggunakan nilai yang dikembalikan membantu kita untuk menghindari perulangan atau melakukan operasi lainnya.

mxcl
sumber
7
Setelah profil sederhana, metode ini sangat cepat. Ratusan kali lebih cepat daripada menggunakan mengurangi (_: _ :), atau bahkan mengurangi (menjadi: _ :)
Kelvin
3
@ Selvin Karena semua algoritma itu O(n^2), dan tidak ada yang memperhatikan.
Alexander - Reinstate Monica
@Kelvin jawaban ini identik dengan jawaban Eneko Alonso + komentar saya (16 Jun '17).
Cœur
27

Cepat 4

Dijamin tetap memesan.

extension Array where Element: Equatable {
    func removingDuplicates() -> Array {
        return reduce(into: []) { result, element in
            if !result.contains(element) {
                result.append(element)
            }
        }
    }
}
Alessandro Martin
sumber
Saya menggunakan ini sekarang, hanya mengubah nama metode untuk removeDuplicates :)
J. Doe
Saya kira solusi ini kompak, tapi saya percaya bahwa solusi deanWombourne diposting tahun sebelumnya mungkin sedikit lebih efisien daripada reduce: keseluruhan, itu hanya satu baris lebih di seluruh proyek Anda untuk menulis fungsi sebagai: var unique: [Iterator.Element] = []; for element in self where !unique.contains(element) { unique.append(element) }; return unique. Saya akui saya belum menguji kinerja relatif.
Cœur
3
Ini akan memiliki O(n²)kinerja waktu, yang sangat buruk untuk array besar.
Duncan C
@NickGaens Tidak, tidak O(n²). Tidak ada yang cepat tentang ini.
Alexander - Reinstate Monica
@ Cœur reduceatau reduce(into:)tidak akan membuat perbedaan kritis. Menulis ulang ini untuk tidak berulang kali menelepon containsakan membuat perbedaan JAUH lebih besar.
Alexander - Reinstate Monica
16

Berikut adalah kategori SequenceTypeyang mempertahankan urutan asli array, tetapi menggunakan a Setuntuk melakukan containspencarian untuk menghindari O(n)biaya pada contains(_:)metode Array .

public extension Sequence where Element: Hashable {

    /// Return the sequence with all duplicates removed.
    ///
    /// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]`
    ///
    /// - note: Taken from stackoverflow.com/a/46354989/3141234, as 
    ///         per @Alexander's comment.
    func uniqued() -> [Element] {
        var seen = Set<Element>()
        return self.filter { seen.insert($0).inserted }
    }
}

Jika Anda tidak Hashable atau Equatable, Anda dapat memberikan predikat untuk melakukan pemeriksaan kesetaraan:

extension Sequence {

    /// Return the sequence with all duplicates removed.
    ///
    /// Duplicate, in this case, is defined as returning `true` from `comparator`.
    ///
    /// - note: Taken from stackoverflow.com/a/46354989/3141234
    func uniqued(comparator: @escaping (Element, Element) throws -> Bool) rethrows -> [Element] {
        var buffer: [Element] = []

        for element in self {
            // If element is already in buffer, skip to the next element
            if try buffer.contains(where: { try comparator(element, $0) }) {
                continue
            }

            buffer.append(element)
        }

        return buffer
    }
}

Sekarang, jika Anda tidak memiliki Hashable, tapi yang equatable, Anda dapat menggunakan metode ini:

extension Sequence where Element: Equatable {

    /// Return the sequence with all duplicates removed.
    ///
    /// i.e. `[ 1, 2, 3, 1, 2 ].uniqued() == [ 1, 2, 3 ]`
    ///
    /// - note: Taken from stackoverflow.com/a/46354989/3141234
    func uniqued() -> [Element] {
        return self.uniqued(comparator: ==)
    }
}

Akhirnya, Anda dapat menambahkan versi jalur kunci unik seperti ini:

extension Sequence {

    /// Returns the sequence with duplicate elements removed, performing the comparison usinig the property at
    /// the supplied keypath.
    ///
    /// i.e.
    ///
    /// ```
    /// [
    ///   MyStruct(value: "Hello"),
    ///   MyStruct(value: "Hello"),
    ///   MyStruct(value: "World")
    ///  ].uniqued(\.value)
    /// ```
    /// would result in
    ///
    /// ```
    /// [
    ///   MyStruct(value: "Hello"),
    ///   MyStruct(value: "World")
    /// ]
    /// ```
    ///
    /// - note: Taken from stackoverflow.com/a/46354989/3141234
    ///
    func uniqued<T: Equatable>(_ keyPath: KeyPath<Element, T>) -> [Element] {
        self.uniqued { $0[keyPath: keyPath] == $1[keyPath: keyPath] }
    }
}

Anda dapat memasukkan keduanya ke dalam aplikasi Anda, Swift akan memilih yang tepat tergantung pada Iterator.Elementjenis urutan Anda .

dekanWombourne
sumber
Heyyy akhirnya seseorang dengan O(n)solusi. Anda dapat menggabungkan set operasi "centang" dan "masukkan" menjadi satu. Lihat stackoverflow.com/a/46354989/3141234
Alexander - Reinstate Monica
Oh, itu pintar :)
deanWombourne
14

Terinspirasi oleh https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift , kita dapat mendeklarasikan alat yang lebih kuat yang mampu memfilter unicity pada keyPath apa pun. Berkat komentar Alexander tentang berbagai jawaban mengenai kompleksitas, solusi di bawah ini harus mendekati optimal.

Solusi non-mutasi

Kami memperluas dengan fungsi yang dapat memfilter untuk unicity pada keyPath apa pun:

extension RangeReplaceableCollection {
    /// Returns a collection containing, in order, the first instances of
    /// elements of the sequence that compare equally for the keyPath.
    func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> Self {
        var unique = Set<T>()
        return filter { unique.insert($0[keyPath: keyPath]).inserted }
    }
}

Catatan: dalam kasus di mana objek Anda tidak sesuai dengan RangeReplaceableCollection, tetapi tidak sesuai dengan Sequence, Anda dapat memiliki ekstensi tambahan ini, tetapi tipe pengembalian akan selalu menjadi Array:

extension Sequence {
    /// Returns an array containing, in order, the first instances of
    /// elements of the sequence that compare equally for the keyPath.
    func unique<T: Hashable>(for keyPath: KeyPath<Element, T>) -> [Element] {
        var unique = Set<T>()
        return filter { unique.insert($0[keyPath: keyPath]).inserted }
    }
}

Pemakaian

Jika kita menginginkan kesatuan untuk elemen itu sendiri, seperti dalam pertanyaan, kita menggunakan keyPath \.self:

let a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
let b = a.unique(for: \.self)
/* b is [1, 4, 2, 6, 24, 15, 60] */

Jika kita menginginkan unicity untuk sesuatu yang lain (seperti untuk idkoleksi benda) maka kita menggunakan keyPath pilihan kita:

let a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
let b = a.unique(for: \.y)
/* b is [{x 1 y 1}, {x 1 y 2}] */

Solusi bermutasi

Kami memperluas dengan fungsi bermutasi yang dapat memfilter untuk unicity pada keyPath apa pun:

extension RangeReplaceableCollection {
    /// Keeps only, in order, the first instances of
    /// elements of the collection that compare equally for the keyPath.
    mutating func uniqueInPlace<T: Hashable>(for keyPath: KeyPath<Element, T>) {
        var unique = Set<T>()
        removeAll { !unique.insert($0[keyPath: keyPath]).inserted }
    }
}

Pemakaian

Jika kita menginginkan kesatuan untuk elemen itu sendiri, seperti dalam pertanyaan, kita menggunakan keyPath \.self:

var a = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
a.uniqueInPlace(for: \.self)
/* a is [1, 4, 2, 6, 24, 15, 60] */

Jika kita menginginkan unicity untuk sesuatu yang lain (seperti untuk idkoleksi benda) maka kita menggunakan keyPath pilihan kita:

var a = [CGPoint(x: 1, y: 1), CGPoint(x: 2, y: 1), CGPoint(x: 1, y: 2)]
a.uniqueInPlace(for: \.y)
/* a is [{x 1 y 1}, {x 1 y 2}] */
Cur
sumber
1
Nah, itu implementasi yang bagus! Saya hanya dengan jalur kunci yang dapat dikonversi ke penutupan, sehingga Anda dapat menggunakan argumen penutupan untuk mendukung kode arbitrer (dalam penutupan) dan hanya melihat properti (melalui jalur kunci). Satu-satunya perubahan yang akan saya buat adalah menjadikan keyPathdefault \.self, karena itu mungkin sebagian besar kasus penggunaan.
Alexander - Reinstate Monica
1
@Alexander Saya mencoba default ke Self, tapi kemudian saya harus Elementselalu membuatnya Hashable. Alternatif untuk nilai default adalah menambahkan overload sederhana tanpa parameter:extension Sequence where Element: Hashable { func unique() { ... } }
Cœur
Ah ya, masuk akal!
Alexander - Pasang kembali Monica
1
Cemerlang ... sederhana, dan terbaik 'fleksibel'. Terima kasih.
BonanzaDriver
12

Solusi alternatif (jika tidak optimal) dari sini menggunakan tipe yang tidak berubah daripada variabel:

func deleteDuplicates<S: ExtensibleCollectionType where S.Generator.Element: Equatable>(seq:S)-> S {
    let s = reduce(seq, S()){
        ac, x in contains(ac,x) ? ac : ac + [x]
    }
    return s
}

Termasuk kontras dengan pendekatan imperatif Jean-Pillippe dengan pendekatan fungsional.

Sebagai bonus, fungsi ini berfungsi dengan string dan juga array!

Sunting: Jawaban ini ditulis pada tahun 2014 untuk Swift 1.0 (sebelumnya Settersedia di Swift). Itu tidak memerlukan kepatuhan Hashable & berjalan dalam waktu kuadratik.

Pliskin
sumber
8
Hati-hati, tidak ada satu, tetapi dua cara ini berjalan dalam waktu kuadratik - keduanya containsdan menambahkan array berjalan di O (n). Meskipun itu memiliki manfaat hanya membutuhkan yang setara, bukan hashable.
Airspeed Velocity
ini cara penulisan yang sangat rumit filter. Ini O (n ^ 2) (yang diperlukan jika Anda tidak ingin membutuhkan Hashablekesesuaian), tetapi Anda setidaknya harus menyebutkannya secara eksplisit
Alexander - Reinstate Monica
10

cepat 2

dengan jawaban fungsi uniq :

func uniq<S: SequenceType, E: Hashable where E==S.Generator.Element>(source: S) -> [E] {
    var seen: [E:Bool] = [:]
    return source.filter({ (v) -> Bool in
        return seen.updateValue(true, forKey: v) == nil
    })
}

menggunakan:

var test = [1,2,3,4,5,6,7,8,9,9,9,9,9,9]
print(uniq(test)) //1,2,3,4,5,6,7,8,9
Daniel Krom
sumber
The BoolNilai jelas berlebihan, sebagai kode Anda tidak pernah membacanya. Gunakan a Setdaripada a Dictionarydan Anda mendapatkan upvote saya.
Nikolai Ruhe
10

Dalam Swift 5

 var array: [String] =  ["Aman", "Sumit", "Aman", "Sumit", "Mohan", "Mohan", "Amit"]

 let uniq = Array(Set(array))
 print(uniq)

Output Akan

 ["Sumit", "Mohan", "Amit", "Aman"]
Sanjay Mishra
sumber
2
Ini adalah pengulangan dari banyak jawaban yang sudah ada di sini, dan tidak mempertahankan pemesanan.
Alexander - Pasang kembali Monica
9

Satu lagi solusi Swift 3.0 untuk menghapus duplikat dari array. Solusi ini meningkat pada banyak solusi lain yang telah diusulkan oleh:

  • Mempertahankan urutan elemen dalam larik input
  • Kompleksitas linear O (n): filter single pass O (n) + set penyisipan O (1)

Diberikan bilangan bulat integer:

let numberArray = [10, 1, 2, 3, 2, 1, 15, 4, 5, 6, 7, 3, 2, 12, 2, 5, 5, 6, 10, 7, 8, 3, 3, 45, 5, 15, 6, 7, 8, 7]

Kode fungsional:

func orderedSet<T: Hashable>(array: Array<T>) -> Array<T> {
    var unique = Set<T>()
    return array.filter { element in
        return unique.insert(element).inserted
    }
}

orderedSet(array: numberArray)  // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]

Kode ekstensi array:

extension Array where Element:Hashable {
    var orderedSet: Array {
        var unique = Set<Element>()
        return filter { element in
            return unique.insert(element).inserted
        }
    }
}

numberArray.orderedSet // [10, 1, 2, 3, 15, 4, 5, 6, 7, 12, 8, 45]

Kode ini mengambil keuntungan dari hasil yang dikembalikan oleh insertoperasi aktif Set, yang dijalankan pada O(1), dan mengembalikan tupel yang menunjukkan apakah item telah dimasukkan atau jika sudah ada dalam set.

Jika item dalam set, filterakan mengecualikannya dari hasil akhir.

Eneko Alonso
sumber
1
Bukan untuk pilih-pilih tetapi Anda akan melakukan tes memasukkan dan keanggotaan sebanyak kali ada elemen sehingga Anda harus menghitung biayanya sebagai O (n) juga. Namun ini tidak berarti 3xO (n) karena O ini dan tidak memiliki biaya yang sama dengan filter sehingga penambahan O (n) adalah apel ke jeruk. Jika kami menganggap operasi yang ditetapkan sebagai O (1) bagian dari biaya filter, kompleksitasnya hanyalah O (n), meskipun dengan "O" yang lebih besar. Mendorong ini hingga batas, Anda juga bisa menghindari penyisipan ketika elemen sudah di set.
Alain T.
Anda benar, menggunakan deferkode akan melakukan operasi uji set dua kali, satu dengan containsdan satu dengan insert. Selanjutnya membaca dokumentasi Swift, saya menemukan bahwa insertmengembalikan tuple yang menunjukkan apakah elemen itu dimasukkan atau tidak, jadi saya telah menyederhanakan kode menghapus containscentang.
Eneko Alonso
2
Bagus. Ekstensi Anda bisa optimal dengan melakukannya padaextension Sequence where Iterator.Element: Hashable { ... }
Cœur
@AlainT. Nggak. Keduanya insertdan containsmemiliki O(1)kompleksitas. O(1) + O(1) = O(1). Kedua operasi ini kemudian dilakukan nkali (sekali per panggilan penutupan dilewati filter, yang disebut sekali per elemen) Yaitu jika operasi membutuhkan jumlah waktu yang konstan terlepas dari ukuran input, kemudian melakukannya dua kali masih membuatnya membutuhkan waktu yang konstan itu terlepas dari ukuran input. Kompleksitas totalnya adalah O(n).
Alexander - Reinstate Monica
9

Swift 4.x:

extension Sequence where Iterator.Element: Hashable {
  func unique() -> [Iterator.Element] {
    return Array(Set<Iterator.Element>(self))
  }

  func uniqueOrdered() -> [Iterator.Element] {
    return reduce([Iterator.Element]()) { $0.contains($1) ? $0 : $0 + [$1] }
  }
}

pemakaian:

["Ljubljana", "London", "Los Angeles", "Ljubljana"].unique()

atau

["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()
Rok Gregorič
sumber
Ini O(n^2). Jangan lakukan ini.
Alexander - Reinstate Monica
8

Cepat 5

extension Sequence where Element: Hashable {
    func unique() -> [Element] {
        NSOrderedSet(array: self as! [Any]).array as! [Element]
    }
}
blackjacx
sumber
Saya melakukan beberapa variasi sehingga saya dapat memilih kunci untuk membandingkan. extension Sequence { // Returns distinct elements based on a key value. func distinct<key: Hashable>(by: ((_ el: Iterator.Element) -> key)) -> [Iterator.Element] { var existing = Set<key>() return self.filter { existing.insert(by($0)).inserted } } }
Marcelo de Aguiar
Tidak perlu menggunakan Bool, ketika satu-satunya nilai yang Anda gunakan adalah true. Anda meraih "tipe unit" (tipe dengan hanya satu nilai yang memungkinkan). Jenis unit Swift adalah Void, yang nilainya hanya ()(alias tuple kosong). Jadi Anda bisa menggunakannya [T: Void]. Meskipun Anda seharusnya tidak melakukan itu, karena pada dasarnya Anda baru saja menemukan Set. Gunakan Setsebagai gantinya. Lihat stackoverflow.com/a/55684308/3141234 Harap hapus jawaban ini.
Alexander - Reinstate Monica
8

Berpikir seperti programmer fungsional :)

Untuk memfilter daftar berdasarkan pada apakah elemen telah terjadi, Anda perlu indeks. Anda dapat menggunakan enumerateduntuk mendapatkan indeks dan mapkembali ke daftar nilai.

let unique = myArray
    .enumerated()
    .filter{ myArray.firstIndex(of: $0.1) == $0.0 }
    .map{ $0.1 }

Ini menjamin pesanan. Jika Anda tidak keberatan dengan urutannya maka jawaban yang ada Array(Set(myArray))lebih sederhana dan mungkin lebih efisien.


PEMBARUAN: Beberapa catatan tentang efisiensi dan kebenaran

Beberapa orang berkomentar tentang efisiensi. Saya pasti di sekolah menulis kode yang benar dan sederhana pertama dan kemudian mencari tahu kemacetan kemudian, meskipun saya menghargai itu masih bisa diperdebatkan apakah ini lebih jelas daripada Array(Set(array)).

Metode ini jauh lebih lambat daripada Array(Set(array)). Seperti yang disebutkan dalam komentar, itu menjaga ketertiban dan bekerja pada elemen yang tidak Hashable.

Namun, metode @Alain T juga menjaga ketertiban dan juga jauh lebih cepat. Jadi kecuali tipe elemen Anda tidak dapat di hashable, atau Anda hanya perlu satu liner cepat, maka saya sarankan menggunakan solusi mereka.

Berikut adalah beberapa tes pada MacBook Pro (2014) pada Xcode 11.3.1 (Swift 5.1) dalam mode Rilis.

Fungsi profiler dan dua metode untuk membandingkan:

func printTimeElapsed(title:String, operation:()->()) {
    var totalTime = 0.0
    for _ in (0..<1000) {
        let startTime = CFAbsoluteTimeGetCurrent()
        operation()
        let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
        totalTime += timeElapsed
    }
    let meanTime = totalTime / 1000
    print("Mean time for \(title): \(meanTime) s")
}

func method1<T: Hashable>(_ array: Array<T>) -> Array<T> {
    return Array(Set(array))
}

func method2<T: Equatable>(_ array: Array<T>) -> Array<T>{
    return array
    .enumerated()
    .filter{ array.firstIndex(of: $0.1) == $0.0 }
    .map{ $0.1 }
}

// Alain T.'s answer (adapted)
func method3<T: Hashable>(_ array: Array<T>) -> Array<T> {
    var uniqueKeys = Set<T>()
    return array.filter{uniqueKeys.insert($0).inserted}
}

Dan sejumlah kecil input uji:

func randomString(_ length: Int) -> String {
  let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  return String((0..<length).map{ _ in letters.randomElement()! })
}

let shortIntList = (0..<100).map{_ in Int.random(in: 0..<100) }
let longIntList = (0..<10000).map{_ in Int.random(in: 0..<10000) }
let longIntListManyRepetitions = (0..<10000).map{_ in Int.random(in: 0..<100) }
let longStringList = (0..<10000).map{_ in randomString(1000)}
let longMegaStringList = (0..<10000).map{_ in randomString(10000)}

Memberikan sebagai output:

Mean time for method1 on shortIntList: 2.7358531951904296e-06 s
Mean time for method2 on shortIntList: 4.910230636596679e-06 s
Mean time for method3 on shortIntList: 6.417632102966309e-06 s
Mean time for method1 on longIntList: 0.0002518167495727539 s
Mean time for method2 on longIntList: 0.021718120217323302 s
Mean time for method3 on longIntList: 0.0005312927961349487 s
Mean time for method1 on longIntListManyRepetitions: 0.00014377200603485108 s
Mean time for method2 on longIntListManyRepetitions: 0.0007293639183044434 s
Mean time for method3 on longIntListManyRepetitions: 0.0001843773126602173 s
Mean time for method1 on longStringList: 0.007168249964714051 s
Mean time for method2 on longStringList: 0.9114790915250778 s
Mean time for method3 on longStringList: 0.015888616919517515 s
Mean time for method1 on longMegaStringList: 0.0525397013425827 s
Mean time for method2 on longMegaStringList: 1.111266262292862 s
Mean time for method3 on longMegaStringList: 0.11214958941936493 s
Tim MB
sumber
1
tidak seperti Array(Set(myArray)), ini bekerja untuk hal-hal yang tidakHashable
Porter Child
1
... dan tidak seperti Array(Set(myArray))urutan array Anda dipertahankan.
Sander Saelmans
Sepertinya jawaban terbaik bagi saya, setidaknya saat ini ketika Swift 5 sudah versi saat ini.
oradyvan
Ini adalah solusi yang sangat elegan; sayangnya, ini juga agak lambat.
Colin Stark
1
@TimMB Oh saya salah membaca posting Anda. Saya melihat adaptasi seseorang yang menggunakannya lastIndex(of:). Saya benar-benar tidak setuju atas kejelasan vs titik optimasi dalam kasus ini. Saya tidak berpikir implementasi ini sangat jelas, terutama dibandingkan dengan solusi berbasis set sederhana. Bagaimanapun, kode tersebut harus diekstraksi ke fungsi ekstensi. Algoritma ini pada dasarnya tidak dapat digunakan bahkan pada ukuran input rendah, seperti pada ribuan hingga puluhan ribu. Tidak sulit untuk menemukan kumpulan data seperti itu, orang dapat memiliki ribuan lagu, file, kontak, dll.
Alexander - Reinstate Monica
6

Untuk array yang elemennya tidak bisa Hashable atau Sebanding (mis. Objek kompleks, kamus atau struct), ekstensi ini menyediakan cara umum untuk menghapus duplikat:

extension Array
{
   func filterDuplicate<T:Hashable>(_ keyValue:(Element)->T) -> [Element]
   {
      var uniqueKeys = Set<T>()
      return filter{uniqueKeys.insert(keyValue($0)).inserted}
   }

   func filterDuplicate<T>(_ keyValue:(Element)->T) -> [Element]
   { 
      return filterDuplicate{"\(keyValue($0))"}
   }
}

// example usage: (for a unique combination of attributes):

peopleArray = peopleArray.filterDuplicate{ ($0.name, $0.age, $0.sex) }

or...

peopleArray = peopleArray.filterDuplicate{ "\(($0.name, $0.age, $0.sex))" }

Anda tidak perlu repot membuat nilai Hashable dan memungkinkan Anda menggunakan kombinasi bidang yang berbeda untuk keunikan.

Catatan: untuk pendekatan yang lebih kuat, silakan lihat solusi yang diusulkan oleh Coeur di komentar di bawah.

stackoverflow.com/a/55684308/1033581

[EDIT] Alternatif 4 cepat

Dengan Swift 4.2 Anda dapat menggunakan kelas Hasher untuk membangun hash lebih mudah. Ekstensi di atas dapat diubah untuk memanfaatkan ini:

extension Array
{
    func filterDuplicate(_ keyValue:((AnyHashable...)->AnyHashable,Element)->AnyHashable) -> [Element]
    {
        func makeHash(_ params:AnyHashable ...) -> AnyHashable
        { 
           var hash = Hasher()
           params.forEach{ hash.combine($0) }
           return hash.finalize()
        }  
        var uniqueKeys = Set<AnyHashable>()
        return filter{uniqueKeys.insert(keyValue(makeHash,$0)).inserted}     
    }
}

Sintaks pemanggilan sedikit berbeda karena closure menerima parameter tambahan yang berisi fungsi untuk meng-hash sejumlah variabel nilai (yang harus Hashable secara individual)

peopleArray = peopleArray.filterDuplicate{ $0($1.name, $1.age, $1.sex) } 

Ini juga akan bekerja dengan nilai keunikan tunggal (menggunakan $ 1 dan mengabaikan $ 0).

peopleArray = peopleArray.filterDuplicate{ $1.name } 
Alain T.
sumber
Ini bisa memberikan hasil acak tergantung pada perilaku "\()", karena mungkin tidak memberi Anda nilai-nilai unik seperti sesuai dengan yang Hashableseharusnya. Contoh, jika elemen Anda sesuai Printabledengan semua yang mengembalikan yang sama description, maka pemfilteran Anda gagal.
Cœur
Sepakat. Pemilihan bidang (atau rumus) yang akan menghasilkan pola keunikan yang diinginkan harus mempertimbangkan hal ini. Untuk banyak kasus penggunaan, ini memberikan solusi ad-hoc sederhana yang tidak memerlukan perubahan kelas atau struct elemen.
Alain T.
2
@AlainT. Jangan lakukan ini, sungguh. Tujuan String bukan untuk menjadi mekanisme pembuatan kunci ghetto ad-hoc. Batasi Tuntuk menjadi Hashable.
Alexander - Reinstate Monica
@Alexander Saya telah menerapkan ide ini dalam jawaban baru: stackoverflow.com/a/55684308/1033581
Cœur
Jawaban sempurna seperti yang saya inginkan. Terima kasih banyak.
Hardik Thakkar
4

Anda bisa menggunakan langsung kumpulan koleksi untuk menghapus duplikat, lalu melemparkannya kembali ke sebuah array

var myArray = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
var mySet = Set<Int>(myArray)

myArray = Array(mySet) // [2, 4, 60, 6, 15, 24, 1]

Kemudian Anda dapat memesan array seperti yang Anda inginkan

myArray.sort{$0 < $1} // [1, 2, 4, 6, 15, 24, 60]
Vincent Choubard
sumber
"Maka Anda dapat memesan array Anda seperti yang Anda inginkan" Bagaimana jika saya ingin pemesanan yang sama seperti dari array asli? Ini tidak semudah itu.
Alexander - Reinstate Monica
3

Versi sintaks yang sedikit lebih ringkas dari jawaban Swift 2 Daniel Krom , menggunakan trailing closure dan nama argumen steno, yang tampaknya didasarkan pada jawaban asli Airspeed Velocity :

func uniq<S: SequenceType, E: Hashable where E == S.Generator.Element>(source: S) -> [E] {
  var seen = [E: Bool]()
  return source.filter { seen.updateValue(true, forKey: $0) == nil }
}

Contoh penerapan tipe khusus yang dapat digunakan dengan uniq(_:)(yang harus sesuai dengan Hashable, dan karenanya Equatable, karena Hashablemeluas Equatable):

func ==(lhs: SomeCustomType, rhs: SomeCustomType) -> Bool {
  return lhs.id == rhs.id // && lhs.someOtherEquatableProperty == rhs.someOtherEquatableProperty
}

struct SomeCustomType {

  let id: Int

  // ...

}

extension SomeCustomType: Hashable {

  var hashValue: Int {
    return id
  }

}

Dalam kode di atas ...

id, seperti yang digunakan dalam overload ==, bisa berupa Equatabletipe apa pun (atau metode yang mengembalikan Equatabletipe, misalnya, someMethodThatReturnsAnEquatableType()). Kode yang dikomentari menunjukkan perpanjangan pemeriksaan untuk kesetaraan, di mana someOtherEquatablePropertyproperti lain dari suatu Equatabletipe (tetapi juga bisa menjadi metode yang mengembalikan Equatabletipe).

id, seperti yang digunakan dalam hashValueproperti yang dihitung (diharuskan untuk menyesuaikan diri Hashable), bisa berupa properti apa pun Hashable(dan dengan demikian Equatable) (atau metode yang mengembalikan suatu Hashabletipe).

Contoh menggunakan uniq(_:):

var someCustomTypes = [SomeCustomType(id: 1), SomeCustomType(id: 2), SomeCustomType(id: 3), SomeCustomType(id: 1)]

print(someCustomTypes.count) // 4

someCustomTypes = uniq(someCustomTypes)

print(someCustomTypes.count) // 3
Scott Gardner
sumber
Tidak perlu menggunakan Bool, ketika satu-satunya nilai yang Anda gunakan adalah true. Anda meraih "tipe unit" (tipe dengan hanya satu nilai yang memungkinkan). Jenis unit Swift adalah Void, yang nilainya hanya ()(alias tuple kosong). Jadi Anda bisa menggunakannya [T: Void]. Meskipun Anda seharusnya tidak melakukan itu, karena pada dasarnya Anda baru saja menemukan Set. Gunakan Setsebagai gantinya. Lihat stackoverflow.com/a/55684308/3141234
Alexander - Reinstate Monica
3

Jika Anda membutuhkan nilai yang diurutkan, ini berfungsi (Swift 4)

let sortedValues = Array(Set(array)).sorted()

Mauricio Chirino
sumber
2
Anda kehilangan pesanan elemen dalam kasus ini.
Shmidt
Tidak sama sekali, untuk apa .sorted()tujuan akhirnya. Salam.
Mauricio Chirino
@MauricioChirino Dan jika array asli Anda itu [2, 1, 1]? Itu akan keluar [1, 2], itu tidak dipesan: p
Alexander - Reinstate Monica
2
@MauricioChirino Tidak, saya tidak. Jika tujuannya adalah untuk menghapus nilai duplikat dari urutan, sambil mempertahankan urutan elemen muncul secara unik, ini tidak melakukan itu. Contoh penghitung yang sangat jelas adalah [2, 1, 1]. Penampilan pertama elemen unik, secara berurutan [2, 1]. Itu jawaban yang benar. Tetapi menggunakan (salah) Anda algoritma, Anda mendapatkan [1, 2], yang adalah diurutkan, tapi tidak dalam yang benar, asli, order.
Alexander - Reinstate Monica
2
Gagal jika elemen dalam arraybukan Hashable; hanya Hashabletipe data yang dapat ditambahkan ke Set, namun tipe data apa pun dapat ditambahkan ke array.
Mecki
3

Ini solusinya

  • Tidak menggunakan NSjenis warisan
  • Cukup cepat dengan O(n)
  • Ringkas
  • Mempertahankan urutan elemen
extension Array where Element: Hashable {

    var uniqueValues: [Element] {
        var allowed = Set(self)
        return compactMap { allowed.remove($0) }
    }
}
Erik Aigner
sumber
2

di sini saya telah melakukan beberapa solusi O (n) untuk objek. Bukan solusi beberapa baris, tapi ...

struct DistinctWrapper <T>: Hashable {
    var underlyingObject: T
    var distinctAttribute: String
    var hashValue: Int {
        return distinctAttribute.hashValue
    }
}
func distinct<S : SequenceType, T where S.Generator.Element == T>(source: S,
                                                                distinctAttribute: (T) -> String,
                                                                resolution: (T, T) -> T) -> [T] {
    let wrappers: [DistinctWrapper<T>] = source.map({
        return DistinctWrapper(underlyingObject: $0, distinctAttribute: distinctAttribute($0))
    })
    var added = Set<DistinctWrapper<T>>()
    for wrapper in wrappers {
        if let indexOfExisting = added.indexOf(wrapper) {
            let old = added[indexOfExisting]
            let winner = resolution(old.underlyingObject, wrapper.underlyingObject)
            added.insert(DistinctWrapper(underlyingObject: winner, distinctAttribute: distinctAttribute(winner)))
        } else {
            added.insert(wrapper)
        }
    }
    return Array(added).map( { return $0.underlyingObject } )
}
func == <T>(lhs: DistinctWrapper<T>, rhs: DistinctWrapper<T>) -> Bool {
    return lhs.hashValue == rhs.hashValue
}

// tests
// case : perhaps we want to get distinct addressbook list which may contain duplicated contacts like Irma and Irma Burgess with same phone numbers
// solution : definitely we want to exclude Irma and keep Irma Burgess
class Person {
    var name: String
    var phoneNumber: String
    init(_ name: String, _ phoneNumber: String) {
        self.name = name
        self.phoneNumber = phoneNumber
    }
}

let persons: [Person] = [Person("Irma Burgess", "11-22-33"), Person("Lester Davidson", "44-66-22"), Person("Irma", "11-22-33")]
let distinctPersons = distinct(persons,
    distinctAttribute: { (person: Person) -> String in
        return person.phoneNumber
    },
    resolution:
    { (p1, p2) -> Person in
        return p1.name.characters.count > p2.name.characters.count ? p1 : p2
    }
)
// distinctPersons contains ("Irma Burgess", "11-22-33") and ("Lester Davidson", "44-66-22")
kas-kad
sumber
1
Daripada menggunakan dengan Setdengan kustom DistinctWrapper, Anda harus menggunakan Dictionarydari differentAttributes ke objek. Ketika Anda mengikuti logika itu sampai tuntas, Anda akhirnya akan mengimplementasikan [ Dictionary.init(_:uniquingKeysWith:)] pastebin.com/w90pVe0p(https://developer.apple.com/documentation/… , yang sekarang dibangun di perpustakaan standar. Lihat betapa sederhananya ini pastebin.com/w90pVe0p
Alexander - Reinstate Monica
2

Saya menggunakan jawaban @ Jean-Philippe Pellet dan membuat ekstensi Array yang melakukan operasi seperti set pada array, sambil mempertahankan urutan elemen.

/// Extensions for performing set-like operations on lists, maintaining order
extension Array where Element: Hashable {
  func unique() -> [Element] {
    var seen: [Element:Bool] = [:]
    return self.filter({ seen.updateValue(true, forKey: $0) == nil })
  }

  func subtract(takeAway: [Element]) -> [Element] {
    let set = Set(takeAway)
    return self.filter({ !set.contains($0) })
  }

  func intersect(with: [Element]) -> [Element] {
    let set = Set(with)
    return self.filter({ set.contains($0) })
  }
}
Will Richardson
sumber
Tidak perlu menggunakan Bool, ketika satu-satunya nilai yang Anda gunakan adalah true. Anda meraih "tipe unit" (tipe dengan hanya satu nilai yang memungkinkan). Jenis unit Swift adalah Void, yang nilainya hanya ()(alias tuple kosong). Jadi Anda bisa menggunakannya [T: Void]. Meskipun Anda seharusnya tidak melakukan itu, karena pada dasarnya Anda baru saja menemukan Set. Gunakan Setsebagai gantinya. Lihat stackoverflow.com/a/55684308/3141234
Alexander - Reinstate Monica
2

Ini hanya implementasi yang sangat sederhana dan nyaman. Properti yang dihitung dalam perluasan Array yang memiliki elemen yang setara.

extension Array where Element: Equatable {
    /// Array containing only _unique_ elements.
    var unique: [Element] {
        var result: [Element] = []
        for element in self {
            if !result.contains(element) {
                result.append(element)
            }
        }

        return result
    }
}
DaveAMoore
sumber
1
Ini juga O(n^2).
Alexander - Reinstate Monica
2
func removeDublicate (ab: [Int]) -> [Int] {
var answer1:[Int] = []
for i in ab {
    if !answer1.contains(i) {
        answer1.append(i)
    }}
return answer1
}

Pemakaian:

let f = removeDublicate(ab: [1,2,2])
print(f)
Jack Rus
sumber
Saya pikir ini yang paling sederhana
Jack Rus
itu membuat pesanan dan memberi Anda array yang Anda inginkan
Jack Rus
Ini juga O(n²).
Alexander - Reinstate Monica
2
  1. Pertama-tama tambahkan semua elemen array ke NSOrderedSet.
  2. Ini akan menghapus semua duplikat dalam array Anda.
  3. Sekali lagi konversikan set ini ke array.

Selesai ....

Contoh

let array = [1,1,1,1,2,2,2,2,4,6,8]

let orderedSet : NSOrderedSet = NSOrderedSet(array: array)

let arrayWithoutDuplicates : NSArray = orderedSet.array as NSArray

output dari arrayWithoutDuplicates - [1,2,4,6,8]

Mahendra Thotakura
sumber
2

Versi singkat yang singkat berdasarkan pada jawaban ekstensi array @ Jean-Philippe Pellet:

extension Array where Element: Hashable {

    var uniques: Array {
        var added = Set<Element>()
        return filter { element in
            defer { added.insert(element) }
            return !added.contains(element)
        }
    }
}
Sander Saelmans
sumber
Ini melakukan dua operasi hashing per elemen, yang tidak perlu. insertmengembalikan tupel yang memberi tahu Anda apakah elemen sudah ada di sana, atau ditambahkan untuk pertama kalinya. stackoverflow.com/a/55684308/3141234 Harap hapus jawaban ini.
Alexander - Reinstate Monica
1

Anda selalu dapat menggunakan Kamus, karena Kamus hanya dapat menyimpan nilai unik. Sebagai contoh:

var arrayOfDates: NSArray = ["15/04/01","15/04/01","15/04/02","15/04/02","15/04/03","15/04/03","15/04/03"]

var datesOnlyDict = NSMutableDictionary()
var x = Int()

for (x=0;x<(arrayOfDates.count);x++) {
    let date = arrayOfDates[x] as String
    datesOnlyDict.setValue("foo", forKey: date)
}

let uniqueDatesArray: NSArray = datesOnlyDict.allKeys // uniqueDatesArray = ["15/04/01", "15/04/03", "15/04/02"]

println(uniqueDatesArray.count)  // = 3

Seperti yang Anda lihat, array yang dihasilkan tidak selalu berada di 'urutan'. Jika Anda ingin mengurutkan / memesan Array, tambahkan ini:

var sortedArray = sorted(datesOnlyArray) {
(obj1, obj2) in

    let p1 = obj1 as String
    let p2 = obj2 as String
    return p1 < p2
}

println(sortedArray) // = ["15/04/01", "15/04/02", "15/04/03"]

.

AT3D
sumber
1

Cara termudah adalah dengan menggunakan NSOrderedSet, yang menyimpan elemen unik dan mempertahankan urutan elemen. Suka:

func removeDuplicates(from items: [Int]) -> [Int] {
    let uniqueItems = NSOrderedSet(array: items)
    return (uniqueItems.array as? [Int]) ?? []
}

let arr = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]
removeDuplicates(from: arr)
sgl0v
sumber
Saya ingin tahu bagaimana kinerja ini dibandingkan dengan jawaban yang lebih baik di sini. Sudahkah Anda membandingkan?
Alexander - Reinstate Monica