स्विफ्ट में एक सरणी से डुप्लिकेट तत्वों को निकालना


252

आजकल स्विफ्ट में आप Set( yourArray )एक सरणी को विशिष्ट बनाने के लिए टाइप करते हैं। (या जरूरत पड़ने पर एक निर्धारित सेट।)

इससे पहले कि यह संभव था, यह कैसे किया गया था?


मेरे पास एक सरणी हो सकती है जो निम्नलिखित की तरह दिखती है:

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

या, वास्तव में, डेटा के समान-टाइप किए गए भागों का कोई भी क्रम। मैं जो करना चाहता हूं वह यह सुनिश्चित करना है कि प्रत्येक समान तत्व में से केवल एक है। उदाहरण के लिए, उपरोक्त सरणी बन जाएगी:

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

ध्यान दें कि 2, 6, और 15 के डुप्लिकेट को यह सुनिश्चित करने के लिए हटा दिया गया था कि प्रत्येक समान तत्व में से केवल एक ही था। क्या स्विफ्ट आसानी से ऐसा करने का एक तरीका प्रदान करता है, या मुझे इसे स्वयं करना होगा?


11
सबसे आसान तरीका है सरणी को एक में बदलना NSSet, एनएसएसटेट वस्तुओं का एक अनियंत्रित संग्रह है, अगर ऑर्डर एनएसओडरडसेट रखने की आवश्यकता है।
एंड्रिया

आप चौराहे के कार्य का उपयोग कर सकते हैं जैसा कि आप इस वर्ग में सरणियों के कार्यों के साथ पा सकते हैं: github.com/pNre/ExSwift/blob/master/ExSwift/Array.swift
एडविन वर्मी

स्विफ्ट का हिस्सा नहीं है लेकिन मैं डॉलर का उपयोग करता हूं। $.uniq(array) github.com/ankurp/Dollar#uniq---unq
एंडी

संभवतः सबसे सुंदर, सबसे स्मार्ट और सबसे तेज़ उत्तर नीचे mxcl के उत्तर द्वारा प्रदान किया गया है। जो आदेश को बनाए रखने में भी मदद करता है
हनी

1
तुम सिर्फ Setस्विफ्ट से उपयोग क्यों नहीं करते ? आप अनियंत्रित और अद्वितीय तत्वों की एक सूची प्रदान करने में सक्षम होंगे।
टिबिअज़

जवाबों:


133

आप अपना स्वयं का रोल कर सकते हैं, जैसे कि ( स्विफ्ट 1.2 के लिए सेट के साथ अपडेट किया गया ):

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]

स्विफ्ट 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
}

और इसके लिए एक एक्सटेंशन के रूप में 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
    }
}

12
आप उस फ़ंक्शन के शरीर को भी लागू कर सकते हैंvar addedDict = [T:Bool](); return filter(source) { addedDict(true, forKey: $0) == nil }
Airspeed वेग

1
@AirspeedVelocity: आपका मतलब है updateValue(true, forKey: $0)...बजायaddedDict(true, forKey: $0)...
Jawwad

1
उफ़ हाँ मुझे खेद है गलती से विधि! return filter(source) { addedDict.updateValue(true, forKey: $0) == nil }जैसा आप कहें वैसा होना चाहिए ।
एयरस्पीड वेलोसिटी

21
बस सावधानी का एक शब्द: इस तरह के सरल कार्यों के लिए प्रदर्शन पर चर्चा करने से बचें जब तक कि आप उनके प्रदर्शन पर निर्भर नहीं करते हैं, जिस बिंदु पर आपको केवल एक चीज करनी चाहिए वह है बेंचमार्क। बहुत बार मैंने धारणा बनाने के कारण अचिन्त्य कोड या इससे भी कम निष्पादन कोड देखा है। :) इसके अलावा, यह शायद समझ में आसान है:let uniques = Array(Set(vals))
Blixt

11
@ ब्लिक्स सहमत। एक बार फिर, यहाँ लाभ मूल सरणी के तत्वों के क्रम का सम्मान करने में निहित है।
जीन-फिलिप पेलेट

493

आप एक सेट में और एक सरणी में फिर से आसानी से परिवर्तित कर सकते हैं:

let unique = Array(Set(originals))

यह सरणी के मूल क्रम को बनाए रखने की गारंटी नहीं है।


37
क्या सरणी के मूल क्रम को संरक्षित करते हुए सेट का उपयोग करने का कोई तरीका है?
Crashalot

6
@ चरसालोट मेरा जवाब देखिए।
जीन-फिलिप पेलेट

5
यदि आपको किसी विशिष्ट संपत्ति द्वारा वस्तुओं को अद्वितीय रखने की आवश्यकता है, तो उस वर्ग पर भी हशेबल और इक्विटेबल प्रोटोकॉल को लागू करने के बजाय, केवल Array-> Set-> Array परिवर्तन
Fawkes

2
अच्छा !! कृपया इस समाधान की समय जटिलता क्या है?
JW.ZG

2
यदि तत्व originalsनहीं हैं Hashable, तो विफल रहता है ; केवल Hashableडेटा प्रकारों को सेट में जोड़ा जा सकता है, फिर भी किसी भी डेटा प्रकार को एक सरणी में जोड़ा जा सकता है।
मिकी

69

कई उत्तर यहां उपलब्ध हैं, लेकिन मैं इस सरल विस्तार से चूक गया, जो स्विफ्ट 2 और इसके लिए उपयुक्त है:

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
    }
}

इसे सुपर सरल बनाता है। इस तरह कहा जा सकता है:

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

गुणों के आधार पर छानना

गुणों के आधार पर किसी सरणी को फ़िल्टर करने के लिए, आप इस विधि का उपयोग कर सकते हैं:

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
    }
}

जिसे आप निम्नानुसार कॉल कर सकते हैं:

let filteredElements = myElements.filterDuplicates { $0.PropertyOne == $1.PropertyOne && $0.PropertyTwo == $1.PropertyTwo }

@ एंटोनी गुण विस्तार के आधार पर फ़िल्टरिंग के लिए धन्यवाद। यह वास्तव में उपयोगी है। लेकिन क्या आप यह बता सकते हैं कि यह कैसे काम करता है। मेरे लिए समझना बहुत मुश्किल है। धन्यवाद
मोस्तफा मोहम्मद Raafat

स्विफ्ट 3 के लिए अपडेट: फंक फिल्टरडुप्लिकेट्स (_ शामिल: पूरक: (_ lhs: तत्व, _ rhs: तत्व) -> बूल) -> [तत्व] {
cbartel

इस उत्तर के पहले भाग ( extension Array where Element: Equatable) को stackoverflow.com/a/36048862/1033581 द्वारा सुपरक्यूट किया जा रहा है जो अधिक शक्तिशाली समाधान ( extension Sequence where Iterator.Element: Equatable) प्रदान करता है ।
कूर

7
यह O(n²)समय प्रदर्शन होगा, जो वास्तव में बड़े सरणियों के लिए खराब है।
डंकन सी।

अब तक देखे गए तत्वों पर नज़र रखने के लिए आपको एक सेट का उपयोग करना चाहिए, इस भयानक O(n²)जटिलता को वापस लाने के लिएO(n)
अलेक्जेंडर - बहाल मोनिका

63

स्विफ्ट 3.0

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))

1
चलो अनूठे नाम = ऐरे (NSOrderedSet (array: userNames)) के रूप में! [स्ट्रिंग] अगर यू के पास स्ट्रिंग है, तो किसी का नहीं
Zaporozhchenko ऑलेक्ज़ेंडर

यदि तत्व arrayनहीं हैं Hashable, तो विफल रहता है ; केवल Hashableडेटा प्रकारों को सेट में जोड़ा जा सकता है, फिर भी किसी भी डेटा प्रकार को एक सरणी में जोड़ा जा सकता है।
मीकई

स्विफ्ट 5.1b5 में परीक्षण किया गया है, यह देखते हुए कि तत्व हस्सबाइल हैं और ऑर्डर को बनाए रखने की इच्छा रखते हैं, NSOrderedSet (array: array) .array फिल्टर के साथ एक सेट का उपयोग करते हुए शुद्ध स्विफ्ट फ़ूंक uniqued () की तुलना में थोड़ा तेज है। मैंने 5100 स्ट्रिंग्स के साथ परीक्षण किया जिसके परिणामस्वरूप 13 अद्वितीय मूल्य थे।
dlemex

62

यदि आप अपने कोड में दोनों एक्सटेंशन डालते हैं, Hashableतो संभव होने पर तेज़ संस्करण का उपयोग किया जाएगा, और Equatableसंस्करण का उपयोग फ़ॉलबैक के रूप में किया जाएगा।

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)
      }
    }
  }
}

यदि आदेश महत्वपूर्ण नहीं है, तो आप हमेशा इस सेट आरंभीक का उपयोग कर सकते हैं ।


ठीक है समझ आ गया। मैं इसे कॉल करने में सक्षम नहीं था क्योंकि मेरी सरणी एक संरचना का एक सरणी है ... मैं इसे अपने मामले में कैसे संभालूंगा? 20 अलग-अलग चर, स्ट्रिंग और [स्ट्रिंग] की संरचना
डेविड

@ डेविड सीकड ऐसा लगता है जैसे आपने अपनी सख्त वाशिकरण या समान नहीं बनाया है। क्या वो सही है?
जेसी

1
@DavidSeek इस तरह, uniqueArray = nonUniqueArray.uniqueElements
Mert Celik

हाँ चिंता मत करो। यह सही काम करने के बाद मिला। अब लगभग 2 साल हो गए हैं: पी
डेविड सीक

इसमें O(n²)समय प्रदर्शन होगा, जो बड़े सरणियों के लिए वास्तव में खराब है।
डंकन सी।

44

संपादित करें / स्विफ्ट 4 या बाद में अपडेट करें

हम RangeReplaceableCollectionप्रोटोकॉल का विस्तार करने के लिए इसे StringProtocolप्रकारों के साथ भी उपयोग करने की अनुमति दे सकते हैं :

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"

उत्परिवर्तन विधि:

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

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

स्विफ्ट 3 के लिए यहां क्लिक करें


1
मुझे यह पसंद है, यह शब्दकोश की एक सरणी के साथ भी काम करता है!
डेयल्डीन सेप

6
O (N ^ 2) बुरा है :(
सिकंदर -

1
@ अलेक्जेंडर लियो डबस ने reduceकार्यान्वयन को बदल दिया है , इसलिए अब जटिलता अलग है।
कूर

1
परिणाम दिलचस्प हैं। 1 मिलियन अनन्य आइटम और 8 मिलियन दोनों के लिए, फ़िल्टर संस्करण तेज़ है। हालाँकि, फ़िल्टर-आधारित संस्करण 8 मिलियन अनूठे आइटम ( O(n)समय के साथ एक बाल ) के लिए 8.38x लंबा समय लेता है, जहाँ फ़्लैटमैप-आधारित संस्करण 1 मिलियन की तुलना में 8 मिलियन अनन्य प्रविष्टियों के लिए 7.47x अधिक समय लेता है, यह सुझाव देता है कि फ़्लैटमैप आधारित संस्करण बेहतर पैमाने पर आता है । किसी तरह फ्लैटमैप आधारित संस्करण O(n)समय से थोड़ा बेहतर करता है !
डंकन सी।

1
वास्तव में, जब मैं सरणी में 64x अधिक वस्तुओं के साथ परीक्षण चलाता हूं, तो फ्लैटमैप आधारित संस्करण तेजी से होता है।
डंकन सी।

43

स्विफ्ट 4

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

के लिए हर प्रयास insertभी एक टपल वापस आ जाएगी: (inserted: Bool, memberAfterInsert: Set.Element)प्रलेखन देखें ।

लौटे मूल्य का उपयोग करने से हमें लूपिंग या किसी अन्य ऑपरेशन से बचने में मदद मिलती है।


7
सरल रूपरेखा के बाद, यह विधि वास्तव में तेज़ है। इसके सैकड़ों गुना तेजी से फिर कम (_: _ :), या यहां तक ​​कि कम करने का उपयोग करके (में: _ :)
केल्विन

3
@ केल्विन क्योंकि उन सभी अन्य एल्गोरिथ्म थे O(n^2), और किसी ने भी गौर नहीं किया।
अलेक्जेंडर - मोनिका

@ केल्विन यह उत्तर एनेको अलोंसो उत्तर + मेरी टिप्पणी (16 जून 17) के समान है।
कूर

27

स्विफ्ट 4

आदेश देते रहने की गारंटी।

extension Array where Element: Equatable {
    func removingDuplicates() -> Array {
        return reduce(into: []) { result, element in
            if !result.contains(element) {
                result.append(element)
            }
        }
    }
}

मैं अब इसका उपयोग करता हूं, केवल हटाने के लिए विधि नाम बदल दिया :)
J. Doe

मुझे लगता है कि यह समाधान कॉम्पैक्ट है, लेकिन मेरा मानना ​​है कि एक साल पहले पोस्ट किया गया deanWombourne समाधान एक की तुलना में थोड़ा अधिक कुशल हो सकता है reduce: कुल मिलाकर, यह आपके पूरे प्रोजेक्ट में सिर्फ एक और पंक्ति है जैसे कि आपका फ़ंक्शन लिखने के लिए var unique: [Iterator.Element] = []; for element in self where !unique.contains(element) { unique.append(element) }; return unique:। मैं मानता हूं कि मैंने अभी तक सापेक्ष प्रदर्शन का परीक्षण नहीं किया है।
Cœur

3
इसमें O(n²)समय प्रदर्शन होगा, जो बड़े सरणियों के लिए वास्तव में खराब है।
डंकन सी।

@NickGaens नहीं यह नहीं है, यह नहीं है O(n²)। इस बारे में कुछ भी तेज़ी से नहीं हुआ है।
अलेक्जेंडर - मोनिका

@ कूर reduceया reduce(into:)एक महत्वपूर्ण अंतर नहीं होगा। बार-बार कॉल न करने के लिए इसे containsफिर से करना एक बहुत बड़ा अंतर होगा।
अलेक्जेंडर - मोनिका

16

यहाँ एक श्रेणी है SequenceTypeजिस पर सरणी का मूल क्रम संरक्षित है, लेकिन एरे की विधि पर लागत से बचने के Setलिए containsलुकअप करने के लिए उपयोग करता है ।O(n)contains(_:)

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 }
    }
}

यदि आप हसबल या इक्विटेबल नहीं हैं, तो आप समानता जांच करने के लिए विधेय में पास कर सकते हैं:

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
    }
}

अब, यदि आपके पास हस्बिक नहीं है, लेकिन समान हैं , तो आप इस विधि का उपयोग कर सकते हैं:

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: ==)
    }
}

अंत में, आप इस तरह से uniqued का एक मुख्य पथ संस्करण जोड़ सकते हैं:

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] }
    }
}

आप अपने ऐप में इन दोनों को चिपका सकते हैं, स्विफ्ट आपके अनुक्रम के Iterator.Elementप्रकार के आधार पर सही का चयन करेगा ।


अरे, आखिरकार एक O(n)समाधान के साथ कोई है। आप "चेक" और "इंसर्ट" सेट ऑपरेशंस को एक में जोड़ सकते हैं, वैसे। देखें stackoverflow.com/a/46354989/3141234
अलेक्जेंडर - मोनिका

ओह, यह चालाक है :)
deanWombourne

15

Https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift से प्रेरित होकर , हम एक और अधिक शक्तिशाली उपकरण की घोषणा कर सकते हैं जो किसी भी कीपथ पर एकता के लिए फ़िल्टर करने में सक्षम है। जटिलता के संबंध में विभिन्न उत्तरों पर अलेक्जेंडर की टिप्पणियों के लिए धन्यवाद, नीचे के समाधान इष्टतम के पास होने चाहिए।

गैर-उत्परिवर्ती समाधान

हम एक ऐसे फ़ंक्शन के साथ विस्तार करते हैं जो किसी भी keyPath पर एकता के लिए फ़िल्टर करने में सक्षम है:

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 }
    }
}

नोट: उस स्थिति में जहां आपकी ऑब्जेक्ट RangeReplaceableCollection के अनुरूप नहीं है, लेकिन अनुक्रम के अनुरूप है, आपके पास यह अतिरिक्त एक्सटेंशन हो सकता है, लेकिन रिटर्न प्रकार हमेशा एक सरणी होगा:

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 }
    }
}

प्रयोग

यदि हम स्वयं तत्वों के लिए एकता चाहते हैं, जैसा कि प्रश्न में है, तो हम 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] */

अगर हम किसी और चीज़ के लिए एकता चाहते हैं (जैसे idवस्तुओं के संग्रह के लिए) तो हम अपनी पसंद के कीथ का उपयोग करते हैं:

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}] */

उत्परिवर्तन समाधान

हम एक परिवर्तनशील फ़ंक्शन के साथ विस्तार करते हैं जो किसी भी keyPath पर एकता के लिए फ़िल्टर करने में सक्षम है:

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 }
    }
}

प्रयोग

यदि हम स्वयं तत्वों के लिए एकता चाहते हैं, जैसा कि प्रश्न में है, तो हम 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] */

अगर हम किसी और चीज़ के लिए एकता चाहते हैं (जैसे idवस्तुओं के संग्रह के लिए) तो हम अपनी पसंद के कीथ का उपयोग करते हैं:

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}] */

1
अब यह एक अच्छा कार्यान्वयन है! मैं केवल उस मुख्य पथ को बंद करने के लिए परिवर्तनीय था, ताकि आप एक मनमाना कोड (बंद करने के लिए) और केवल संपत्ति देखने के अप (कुंजी पथ के माध्यम से) का समर्थन करने के लिए एक क्लोजर arg का उपयोग कर सकें। केवल मैं जो परिवर्तन करूंगा, वह keyPathडिफ़ॉल्ट रूप से बनाना है \.self, क्योंकि संभवतः अधिकांश उपयोग के मामले हैं।
अलेक्जेंडर - मोनिका

1
@Alexander मैंने स्वयं को डिफ़ॉल्ट करने की कोशिश की, लेकिन फिर मुझे Elementहमेशा बनाने की आवश्यकता होगी Hashable। डिफ़ॉल्ट मान का एक विकल्प मापदंडों के बिना एक साधारण अधिभार जोड़ रहा है:extension Sequence where Element: Hashable { func unique() { ... } }
C'ur

आह हाँ, समझ में आता है!
अलेक्जेंडर - मोनिका

1
शानदार ... सरल, और सभी 'लचीले' से बेहतरीन। धन्यवाद।
बोनांजाड्राइवर

12

वैरिएबल के बजाय अपरिवर्तनीय प्रकारों का उपयोग करके यहां से एक वैकल्पिक (यदि इष्टतम नहीं है) :

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
}

एक कार्यात्मक दृष्टिकोण के साथ जीन-पिल्लिप के अनिवार्य दृष्टिकोण के विपरीत शामिल है।

एक बोनस के रूप में यह फ़ंक्शन स्ट्रिंग्स के साथ-साथ सरणियों के साथ काम करता है!

संपादित करें: यह उत्तर 2014 में स्विफ्ट 1.0 (इससे पहले Setस्विफ्ट में उपलब्ध था) के लिए लिखा गया था। यह द्विघात समय में चलने योग्य और चलने की आवश्यकता नहीं है।


8
खबरदार, एक नहीं हैं, लेकिन दो तरीकों से यह द्विघात समय में चलता है - दोनों containsऔर सरणी परिशिष्ट O (n) में चलते हैं। हालाँकि इसमें केवल समतुल्य की आवश्यकता होती है, न कि धोने योग्य।
एयरस्पीड वेलोसिटी

यह लेखन का एक बहुत जटिल तरीका है filter। यह O (n ^ 2) है (जो आवश्यकता है यदि आप Hashableअनुरूपता की आवश्यकता नहीं चाहते हैं ), लेकिन आपको कम से कम कॉल करना चाहिए कि स्पष्ट रूप से
अलेक्जेंडर - मोनिका

10

तेज 2

साथ 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
    })
}

उपयोग:

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

Boolमूल्य जाहिर है, बेमानी है के रूप में अपने कोड यह कभी नहीं पढ़ता है। एक के Setबजाय का उपयोग करें Dictionaryऔर आप मेरे उत्थान मिलता है।
निकोलाई रुहे

10

स्विफ्ट 5 में

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

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

आउटपुट होगा

 ["Sumit", "Mohan", "Amit", "Aman"]

2
यह यहाँ पहले से ही कई उत्तरों की पुनरावृत्ति है, और यह आदेश को संरक्षित नहीं करता है।
अलेक्जेंडर - मोनिका

9

सरणी से डुप्लिकेट को निकालने के लिए एक और स्विफ्ट 3.0 समाधान। यह समाधान पहले से प्रस्तावित कई अन्य समाधानों में सुधार करता है:

  • इनपुट ऐरे में तत्वों के क्रम को संरक्षित करना
  • रैखिक जटिलता O (n): एकल पास फ़िल्टर O (n) + सेट सम्मिलन O (1)

पूर्णांक सरणी को देखते हुए:

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]

कार्यात्मक कोड:

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]

ऐरे एक्सटेंशन कोड:

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]

यह कोड उस insertऑपरेशन द्वारा लौटाए गए परिणाम का लाभ उठाता है Set, जिस पर अमल होता है O(1), और यह दर्शाता है कि आइटम डाला गया था या यदि यह पहले से ही सेट में मौजूद था, तो एक टपल लौटाता है।

यदि आइटम सेट में था, filterतो इसे अंतिम परिणाम से बाहर कर देगा।


1
Picky होने के लिए नहीं, लेकिन आप सम्मिलित रूप से और सदस्यता परीक्षण का प्रदर्शन कर रहे हैं क्योंकि कई बार तत्व हैं इसलिए आपको उनकी लागत को O (n) के रूप में अच्छी तरह से गिनना चाहिए। इसका मतलब यह नहीं है कि 3xO (n) हालांकि ये O के हैं और फिल्टर के बराबर लागत नहीं है इसलिए O (n) के जोड़ संतरे के लिए सेब है। यदि हम सेट ऑपरेशंस को फ़िल्टर लागत का एक O (1) हिस्सा मानते हैं, तो जटिलता केवल O (n) है, यद्यपि एक बड़ा "O"। इस सीमा तक धकेलने से, आप आवेषण से बच सकते हैं जब तत्व पहले से ही सेट में है।
एलन टी।

आप सही हैं, deferकोड का उपयोग करते हुए सेट टेस्ट ऑपरेशन दो बार करेंगे, एक के साथ containsऔर एक के साथ insert। इसके अलावा स्विफ्ट प्रलेखन को पढ़ते हुए, मैंने पाया कि insertतत्व को सम्मिलित किया गया था या नहीं यह इंगित करता है कि एक ट्यूपल लौटाता है, इसलिए मैंने containsचेक को हटाने वाले कोड को सरल बनाया है ।
एनेको अलोंसो

2
अच्छा लगा। आपका विस्तार इसे करने में इष्टतम हो सकता हैextension Sequence where Iterator.Element: Hashable { ... }
C couldur

@AlainT। नहीं। दोनों insertऔर containsहै O(1)जटिलता। O(1) + O(1) = O(1)। इन दो ऑपरेशनों को nकई बार किया जाता है (एक बार बंद होने के बाद कॉल किया जाता है filter, जिसे प्रति तत्व एक बार कहा जाता है) Ie यदि किसी ऑपरेशन में इनपुट आकार की परवाह किए बिना लगातार समय लगता है, तो इसे दो बार करने के बाद भी इसे स्थिर समय लगता है इनपुट आकार की परवाह किए बिना। इसकी कुल जटिलता है O(n)
अलेक्जेंडर - मोनिका

9

स्विफ्ट 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] }
  }
}

उपयोग:

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

या

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

यह वह जगह है O(n^2)। यह मत करो।
अलेक्जेंडर - मोनिका

8

स्विफ्ट 5

extension Sequence where Element: Hashable {
    func unique() -> [Element] {
        NSOrderedSet(array: self as! [Any]).array as! [Element]
    }
}

मैंने कुछ बदलाव किए ताकि मैं तुलना करने के लिए एक कुंजी चुन सकूं। 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 } } }
मार्सेलो डे अगुइर

Boolजब आपके द्वारा उपयोग किया जाने वाला एकमात्र मूल्य है, तो ए का उपयोग करने की कोई आवश्यकता नहीं है true। आप एक "यूनिट प्रकार" (केवल एक संभावित मूल्य के साथ एक प्रकार) के लिए पहुंच रहे हैं। स्विफ्ट का यूनिट प्रकार है Void, जिसका एकमात्र मूल्य ()(उर्फ टुपल उर्फ) है। तो आप बस उपयोग कर सकते हैं [T: Void]। हालांकि आपको ऐसा नहीं करना चाहिए, क्योंकि आपने मूल रूप से सिर्फ आविष्कार किया है SetSetइसके बजाय उपयोग करें । देखें stackoverflow.com/a/55684308/3141234 कृपया इस उत्तर को हटा दें।
अलेक्जेंडर - मोनिका

8

एक कार्यात्मक प्रोग्रामर की तरह सोचें :)

तत्व पहले से मौजूद है या नहीं इसके आधार पर सूची को फ़िल्टर करने के लिए, आपको सूचकांक की आवश्यकता है। आप enumeratedसूचकांक प्राप्त करने और mapमूल्यों की सूची में वापस जाने के लिए उपयोग कर सकते हैं ।

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

यह आदेश की गारंटी देता है। यदि आप आदेश के बारे में बुरा नहीं मानते हैं तो मौजूदा उत्तर Array(Set(myArray))सरल और शायद अधिक कुशल है।


अद्यतन: दक्षता और शुद्धता पर कुछ नोट्स

कुछ लोगों ने दक्षता पर टिप्पणी की है। मैं निश्चित रूप से पहले सही और सरल कोड लिखने के स्कूल में हूं और फिर बाद में अड़चनें पैदा कर रहा हूं, हालांकि मैं इसकी सराहना करता हूं कि यह बहस करने योग्य है कि क्या यह स्पष्ट है Array(Set(array))

यह विधि की तुलना में बहुत धीमी है Array(Set(array))। जैसा कि टिप्पणियों में उल्लेख किया गया है, यह ऑर्डर को संरक्षित करता है और उन तत्वों पर काम करता है जो हसबल नहीं हैं।

हालाँकि, @Alain T का तरीका ऑर्डर को संरक्षित भी करता है और बहुत तेज़ भी है। तो जब तक आपके तत्व प्रकार को धोने योग्य नहीं है, या आपको बस एक त्वरित लाइनर की आवश्यकता है, तो मैं उनके समाधान के साथ जाने का सुझाव दूंगा।

रिलीज़ मोड में Xcode 11.3.1 (स्विफ्ट 5.1) पर मैकबुक प्रो (2014) पर कुछ परीक्षण दिए गए हैं।

प्रोफाइलर फ़ंक्शन और तुलना करने के दो तरीके:

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}
}

और परीक्षण इनपुट की एक छोटी विविधता:

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)}

आउटपुट के रूप में देता है:

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

1
इसके विपरीत Array(Set(myArray)), यह उन चीजों के लिए काम करता है जो नहीं हैंHashable
पोर्टर चाइल्ड

1
... और Array(Set(myArray))आपके सरणी के क्रम के विपरीत बनाए रखा जाता है।
सांडेर सेलामन

यह मेरे लिए सबसे अच्छा उत्तर की तरह दिखता है, कम से कम वर्तमान में जब स्विफ्ट 5 पहले से ही वर्तमान संस्करण है।
oradyvan

यह एक बहुत ही सुंदर समाधान है; दुर्भाग्य से, यह भी धीमी है।
कॉलिन स्टार्क

1
@ टिम ओम ओह मैंने आपकी पोस्ट को गलत बताया। मैंने किसी के अनुकूलन को देखा जो इस्तेमाल किया lastIndex(of:)। मैं इस मामले में स्पष्टता बनाम अनुकूलन बिंदु पर पूरी तरह असहमत हूं। मुझे नहीं लगता कि यह कार्यान्वयन विशेष रूप से स्पष्ट है, विशेष रूप से एक साधारण सेट-आधारित समाधान की तुलना में। किसी भी स्थिति में, इस तरह के कोड को एक विस्तार समारोह में निकाला जाना चाहिए। यह एल्गोरिथ्म मूल रूप से कम इनपुट आकार में भी अनुपयोगी हो जाता है, जैसे हजारों से हजारों में। इस तरह के डेटा सेट को ढूंढना मुश्किल नहीं है, लोगों के पास हजारों गाने, फाइलें, संपर्क आदि हो सकते हैं
अलेक्जेंडर -

6

उन सरणियों के लिए जहां तत्व न तो हस्सिबल हैं और न ही तुलनीय (जैसे जटिल वस्तुएं, शब्दकोष या संरचनाएं), यह विस्तार डुप्लिकेट को हटाने के लिए एक सामान्यीकृत तरीका प्रदान करता है:

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))" }

आपको मूल्‍यवान बनाने के लिए परेशान नहीं होना है और यह आपको विशिष्टता के लिए विभिन्न संयोजनों का उपयोग करने की अनुमति देता है।

नोट: अधिक मजबूत दृष्टिकोण के लिए, कृपया नीचे टिप्पणी में Coeur द्वारा प्रस्तावित समाधान देखें।

stackoverflow.com/a/55684308/1033581

[संपादित करें] स्विफ्ट 4 विकल्प

Swift 4.2 के साथ आप हैश क्लास का उपयोग करके हैश को बहुत आसान बना सकते हैं। इसका लाभ उठाने के लिए उपरोक्त एक्सटेंशन को बदला जा सकता है:

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}     
    }
}

कॉलिंग सिंटैक्स थोड़ा अलग है क्योंकि क्लोज़र को एक अतिरिक्त पैरामीटर प्राप्त होता है जिसमें फ़ंक्शन को मानों की एक चर संख्या है (जो व्यक्तिगत रूप से उपलब्ध होनी चाहिए)

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

यह एकल विशिष्टता मूल्य ($ 1 का उपयोग करके और $ 0 की अनदेखी) के साथ भी काम करेगा।

peopleArray = peopleArray.filterDuplicate{ $1.name } 

यह व्यवहार के आधार पर यादृच्छिक परिणाम दे सकता है "\()", क्योंकि हो सकता है कि यह आपको अनूठे मूल्यों की तरह न दे Hashable। उदाहरण के लिए, यदि आपके तत्व Printableसभी को समान करके लौटाते हैं description, तो आपका फ़िल्टरिंग विफल हो जाता है।
कूर

माना। उन क्षेत्रों (या सूत्र) का चयन जो वांछित विशिष्टता पैटर्न का उत्पादन करेंगे, उन्हें इसे ध्यान में रखना होगा। कई उपयोग के मामलों के लिए, यह एक सरल तदर्थ समाधान प्रदान करता है जिसके लिए तत्व के वर्ग या संरचना में कोई परिवर्तन नहीं करना पड़ता है।
एलेन टी।

2
@AlainT। ऐसा मत करो, सच में। स्ट्रिंग का उद्देश्य कुछ यहूदी बस्ती तदर्थ प्रमुख पीढ़ी तंत्र नहीं है। सिर्फ होने के Tलिए विवश Hashable
अलेक्जेंडर - मोनिका

@Alexander मैंने इस विचार को एक नए उत्तर में लागू किया है: stackoverflow.com/a/55684308/1033581
C

जैसा मैं चाहता हूं, बिल्कुल सही जवाब। बहुत बहुत धन्यवाद।
हार्दिक ठक्कर

4

आप डुप्लिकेट को निकालने के लिए सीधे एक सेट संग्रह का उपयोग कर सकते हैं, फिर इसे एक सरणी में वापस डाल सकते हैं

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]

फिर आप अपनी सरणी को अपनी इच्छानुसार ऑर्डर कर सकते हैं

myArray.sort{$0 < $1} // [1, 2, 4, 6, 15, 24, 60]

"फिर आप अपने सरणी को ऑर्डर कर सकते हैं जैसा आप चाहते हैं" क्या होगा यदि मैं मूल सरणी से समान ऑर्डर करना चाहता हूं? यह इतना आसान नहीं है।
अलेक्जेंडर -

3

डैनियल क्रॉम की स्विफ्ट 2 उत्तर का थोड़ा अधिक सक्सेना सिंटैक्स संस्करण , एक अनुगामी क्लोजर और शॉर्टहैंड तर्क नाम का उपयोग करके, जो एयरस्पीड वेलोसिटी के मूल उत्तर पर आधारित प्रतीत होता है :

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 }
}

एक कस्टम प्रकार को लागू करने का उदाहरण, जिसका उपयोग किया जा सकता है uniq(_:)(जो इसके अनुरूप होना चाहिए Hashable, और इस प्रकार Equatable, क्योंकि Hashableविस्तार होता है 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
  }

}

उपरोक्त कोड में ...

id, जैसा कि ओवरलोड में उपयोग किया जाता है ==, कोई भी Equatableप्रकार हो सकता है (या विधि जो एक Equatableप्रकार का रिटर्न देता है , जैसे, someMethodThatReturnsAnEquatableType())। टिप्पणी-आउट कोड समानता के लिए चेक का विस्तार करता है, जहां someOtherEquatablePropertyएक Equatableप्रकार की एक और संपत्ति है (लेकिन यह भी एक विधि हो सकती है जो एक Equatableप्रकार का रिटर्न देती है )।

id, जैसा कि hashValueगणना की गई संपत्ति में उपयोग किया जाता है (अनुरूप करने के लिए आवश्यक Hashable), कोई भी Hashable(और इस प्रकार Equatable) संपत्ति (या विधि जो एक Hashableप्रकार का रिटर्न देती है ) हो सकती है।

उपयोग करने का उदाहरण 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

Boolजब आपके द्वारा उपयोग किया जाने वाला एकमात्र मूल्य है, तो ए का उपयोग करने की कोई आवश्यकता नहीं है true। आप एक "यूनिट प्रकार" (केवल एक संभावित मूल्य के साथ एक प्रकार) के लिए पहुंच रहे हैं। स्विफ्ट का यूनिट प्रकार है Void, जिसका एकमात्र मूल्य ()(उर्फ टुपल उर्फ) है। तो आप बस उपयोग कर सकते हैं [T: Void]। हालांकि आपको ऐसा नहीं करना चाहिए, क्योंकि आपने मूल रूप से सिर्फ आविष्कार किया है SetSetइसके बजाय उपयोग करें । देखें stackoverflow.com/a/55684308/3141234
अलेक्जेंडर - मोनिका

3

मामले में आपको हल किए गए मान चाहिए, यह काम करता है (स्विफ्ट 4)

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


2
आप इस मामले में तत्वों के आदेश को खो देते हैं।
श्मिट

बिलकुल नहीं, यही .sorted()आखिर में है। सादर।
मारीशियो चिरिनो

@MauricioChirino और यदि आपका मूल सरणी था [2, 1, 1]? यह पता चलेगा [1, 2], यह आदेश नहीं दिया गया है: p
अलेक्जेंडर - मोनिका

2
@MauricioChirino नहीं, मैं नहीं। यदि लक्ष्य एक अनुक्रम से डुप्लिकेट मानों को निकालना है, तो उस क्रम को बरकरार रखना जिसमें तत्व विशिष्ट रूप से प्रकट हुए हैं, यह ऐसा नहीं करता है। बहुत स्पष्ट काउंटर उदाहरण है [2, 1, 1]। अद्वितीय तत्वों की पहली उपस्थिति, क्रम में है [2, 1]। यही सही जवाब है। लेकिन अपने (गलत) कलन विधि का उपयोग, आप प्राप्त [1, 2]है, जो है छाँटे गए, लेकिन नहीं है सही, मूल, क्रम में।
अलेक्जेंडर -

2
यदि तत्व arrayनहीं हैं Hashable, तो विफल रहता है ; केवल Hashableडेटा प्रकारों को सेट में जोड़ा जा सकता है, फिर भी किसी भी डेटा प्रकार को एक सरणी में जोड़ा जा सकता है।
मीकई

3

यहाँ एक समाधान है कि

  • कोई विरासत NSप्रकार का उपयोग करता है
  • के साथ यथोचित उपवास है O(n)
  • संक्षिप्त है
  • तत्व आदेश को संरक्षित करता है
extension Array where Element: Hashable {

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

2

यहाँ मैंने वस्तुओं के लिए कुछ O (n) समाधान किया है। कुछ लाइनों का हल नहीं, लेकिन ...

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")

1
Setकस्टम के साथ उपयोग करने के बजाय DistinctWrapper, आपको Dictionaryअलग-अलग विशेषताओं से वस्तुओं का उपयोग करना चाहिए । जब आप उस तर्क का अनुसरण करते हैं, तो आप अंततः [ Dictionary.init(_:uniquingKeysWith:)] pastebin.com/w90pVe0p(https://developer.apple.com/documentation/… , को लागू करना समाप्त कर देंगे , जो अब मानक पुस्तकालय में बनाया गया है। यह सरल है। pastebin.com/w90pVe0p
अलेक्जेंडर - मोनिका

2

मैंने @ जीन-फिलिप पेलेट के उत्तर का उपयोग किया और एक एरियर एक्सटेंशन किया जो तत्वों के क्रम को बनाए रखते हुए सरणियों पर सेट-जैसे ऑपरेशन करता है।

/// 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) })
  }
}

Boolजब आपके द्वारा उपयोग किया जाने वाला एकमात्र मूल्य है, तो ए का उपयोग करने की कोई आवश्यकता नहीं है true। आप एक "यूनिट प्रकार" (केवल एक संभावित मूल्य के साथ एक प्रकार) के लिए पहुंच रहे हैं। स्विफ्ट का यूनिट प्रकार है Void, जिसका एकमात्र मूल्य ()(उर्फ टुपल उर्फ) है। तो आप बस उपयोग कर सकते हैं [T: Void]। हालांकि आपको ऐसा नहीं करना चाहिए, क्योंकि आपने मूल रूप से सिर्फ आविष्कार किया है SetSetइसके बजाय उपयोग करें । देखें stackoverflow.com/a/55684308/3141234
अलेक्जेंडर - मोनिका

2

यह सिर्फ एक बहुत ही सरल और सुविधाजनक कार्यान्वयन है। एक एरे के विस्तार में एक गणना की गई संपत्ति जिसमें समान तत्व हैं।

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
    }
}

1
यह भी है O(n^2)
अलेक्जेंडर - मोनिका

2
func removeDublicate (ab: [Int]) -> [Int] {
var answer1:[Int] = []
for i in ab {
    if !answer1.contains(i) {
        answer1.append(i)
    }}
return answer1
}

उपयोग:

let f = removeDublicate(ab: [1,2,2])
print(f)

मुझे लगता है कि यह सबसे सरल है
जैक रस

यह आदेश रखता है और आपको एक सरणी देता है जो आप चाहते हैं
जैक रस

यह भी है O(n²)
अलेक्जेंडर -

2
  1. पहले सरणी के सभी तत्वों को NSOrderedSet में जोड़ें।
  2. यह आपके सरणी में सभी डुप्लिकेट को निकाल देगा।
  3. फिर से इस क्रम को एक सरणी में बदलें।

किया हुआ....

उदाहरण

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

arrayWithoutDuplicates का उत्पादन - [1,2,4,6,8]


2

@ जीन-फिलिप पेलेट के सरणी विस्तार उत्तर पर आधारित एक छोटा छोटा संस्करण:

extension Array where Element: Hashable {

    var uniques: Array {
        var added = Set<Element>()
        return filter { element in
            defer { added.insert(element) }
            return !added.contains(element)
        }
    }
}

यह प्रति तत्व दो हैशिंग ऑपरेशन करता है, जो अनावश्यक है। insertएक टपल लौटाता है जो आपको बताता है कि क्या तत्व पहले से मौजूद था, या पहली बार जोड़ा गया था। stackoverflow.com/a/55684308/3141234 कृपया इस उत्तर को हटा दें।
अलेक्जेंडर - मोनिका

1

आप हमेशा एक डिक्शनरी का उपयोग कर सकते हैं, क्योंकि एक डिक्शनरी केवल अनोखे मूल्यों को धारण कर सकती है। उदाहरण के लिए:

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

जैसा कि आप देख सकते हैं, परिणामस्वरूप सरणी हमेशा 'ऑर्डर' में नहीं होगी। यदि आप ऐरे को क्रमबद्ध / क्रमबद्ध करना चाहते हैं, तो इसे जोड़ें:

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"]


1

सबसे आसान तरीका NSOrderedSet का उपयोग करना होगा, जो अद्वितीय तत्वों को संग्रहीत करता है और तत्वों के आदेश को संरक्षित करता है। पसंद:

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)

मुझे आश्चर्य है कि यह प्रदर्शन यहाँ पर बेहतर उत्तरों की तुलना कैसे करता है। क्या आपने तुलना की है?
अलेक्जेंडर - मोनिका
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.