সুইফটে একটি অ্যারের থেকে সদৃশ উপাদানগুলি সরানো


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, এনএসএসেট হ'ল এনএসআরার্ডসেট অর্ডার রাখার প্রয়োজনে অবজেক্টগুলির একটি আনর্ডারড সংগ্রহ।
Andrea

এই ক্লাসে অ্যারেগুলির জন্য ফাংশনগুলি যেমন আপনি দেখতে পাবেন তেমন ছেদ ফাংশনটি আপনি ব্যবহার করতে পারেন: github.com/pNre/ExSwift/blob/master/ExSwift/Array.swift
এডউইন

সুইফটের অংশ নয় তবে আমি ডলার ব্যবহার করি। $.uniq(array) github.com/ankurp/Dollar#uniq---uniq
অ্যান্ডি

সম্ভবত সবচেয়ে মার্জিত, স্মার্ট এবং দ্রুত উত্তর নীচে এমএক্সসিএল এর উত্তর দ্বারা সরবরাহ করা হয়েছে । যা শৃঙ্খলা বজায় রাখতেও সহায়তা করে
মধু

1
আপনি কেবল Setসুইফ্ট থেকে কেন ব্যবহার করবেন না ? আপনি অর্ডারযুক্ত এবং অনন্য উপাদানের একটি তালিকা সরবরাহ করতে সক্ষম হবেন।
টিবিয়াজেড

উত্তর:


133

আপনি নিজের রোল করতে পারেন, উদাহরণস্বরূপ ( সেট সহ সুইফট ১.২ এর জন্য আপডেট করা ):

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 }
শৃঙ্খলা রূপায়ণও করতে পারেন

1
@ আর্স্পিডভেলসিটি: আপনি কি এর updateValue(true, forKey: $0)...পরিবর্তেaddedDict(true, forKey: $0)...
জাওয়াদ

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
অ্যারের মূল ক্রম সংরক্ষণের সময় কোনও সেট ব্যবহার করার কোনও উপায় আছে কি?
ক্র্যাশলোট

6
আমার উত্তর দেখুন
জিন-ফিলিপ পেলিট 18

5
আপনার যদি কোনও নির্দিষ্ট সম্পত্তি দ্বারা অবজেক্টগুলি অনন্য রাখতে হয় তবে কেবলমাত্র অ্যারে-> সেট-> অ্যারে রূপান্তরটি ব্যবহার না করে class শ্রেণিতে হাস্যাবল এবং ইক্যুটেটেবল প্রোটোকল প্রয়োগ করে
ফকস

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 }

@ এন্টাইন প্রপার্টি এক্সটেনশনের ভিত্তিতে ফিল্টারিংয়ের জন্য আপনাকে ধন্যবাদ। এটা সত্যিই দরকারী। তবে আপনি কী দয়া করে তা ব্যাখ্যা করতে পারেন। এটা আমার পক্ষে বোঝা খুব কঠিন। আপনাকে ধন্যবাদ
মোস্তফা মোহাম্মদ রাফাত

সুইফট 3 এর জন্য আপডেটগুলি: ফানক ফিল্টার ডুপ্লিকেটস (_ অন্তর্ভুক্ত উপাদান: (_ এলএইচএস: এলিমেন্ট, _ আরএইচএস: উপাদান) -> বুল) -> [উপাদান]
c

এই উত্তরের ( extension Array where Element: Equatable) প্রথম অংশটি স্ট্যাকওভারফ্লো.com/ a/ 36048862/10/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
যাক অনন্য অর্ডারডনেমস = অ্যারে (এনএসআরআরডসেট (অ্যারে: ইউজারনেম)) হিসাবে! [স্ট্রিং] আপনার যদি স্ট্রিংয়ের অ্যারে থাকে তবে কারও নয়
জাপোরোজচেনকো ওলেকসান্দ্র

উপাদানগুলি না থাকলে ব্যর্থ arrayহয় Hashable; Hashableএকটি সেটে কেবল ডেটা টাইপ যুক্ত করা যায়, তবুও কোনও ডাটা টাইপ অ্যারেতে যোগ করা যায়।
মক্কি

সুইফট 5.1b5 তে পরীক্ষা করা হয়েছে, যে উপাদানগুলি হ্যাশেবল এবং ক্রম বজায় রাখার আকাঙ্ক্ষা, এনএসআরআরডসেট (অ্যারে: অ্যারে) .আরে ফিল্টার সহ একটি সেট ব্যবহার করে খাঁটি সুইফ্ট ফানক ইউনিকড () এর তুলনায় সামান্য দ্রুত। আমি 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
ও (এন ^ 2) খারাপ :(
আলেকজান্ডার - মনিকা

1
@ আলেকজান্ডার লিও ডাবস reduceবাস্তবায়নটি প্রতিস্থাপন করেছেন , তাই এখন জটিলতা আলাদা।
সিউর

1
ফলাফল আকর্ষণীয়। 1 মিলিয়ন অনন্য আইটেম এবং 8 মিলিয়ন উভয়ের জন্যই ফিল্টার সংস্করণটি দ্রুত। যাইহোক, ফিল্টার-ভিত্তিক সংস্করণটি 8 মিলিয়ন অনন্য আইটেমের (সময়ের সাথে সাথে একটি চুলের O(n)) জন্য 8.38x দীর্ঘ সময় নেয়, যেখানে ফ্ল্যাটম্যাপ-ভিত্তিক সংস্করণটি 1 মিলিয়নের চেয়ে 8 মিলিয়ন অনন্য এন্ট্রিগুলির জন্য 7.47x বেশি সময় নেয়, যা প্রস্তাব দেয় যে ফ্ল্যাটম্যাপ ভিত্তিক সংস্করণটি আরও ভাল স্কেল করে । কোনওভাবে ফ্ল্যাটম্যাপ ভিত্তিক সংস্করণ O(n)সময়ের চেয়ে কিছুটা ভাল করে !
ডানকান সি

1
আসলে, যখন আমি অ্যারেতে আরও x৪x আরও আইটেম দিয়ে পরীক্ষা চালাই, তখন ফ্ল্যাটম্যাপ ভিত্তিক সংস্করণটি দ্রুত হয়।
ডানকান সি

43

সুইফট 4

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

প্রতিটি প্রচেষ্টাই insertএকটি tuple আসতে হবে: (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)
            }
        }
    }
}

আমি এটি এখনই ব্যবহার করি, ডুপ্লিকেটগুলি অপসারণের জন্য কেবল পদ্ধতির নাম পরিবর্তন করেছি :)
জে

আমি এই সমাধান কম্প্যাক্ট, কিন্তু আমি বিশ্বাস করি যে deanWombourne সমাধান পোস্ট এক বছর আগের হতে পারে সামান্য বেশি দক্ষ একটি চেয়ে reduce: সামগ্রিক, এটি আপনার পুরো প্রকল্প হিসেবে আপনার ফাংশন লিখতে শুধু একটা আরো লাইন: var unique: [Iterator.Element] = []; for element in self where !unique.contains(element) { unique.append(element) }; return unique। আমি স্বীকার করি যে আমি এখনও আপেক্ষিক পারফরম্যান্স পরীক্ষা করিনি।
সিউর

3
এটির O(n²)সময় পারফরম্যান্স থাকবে যা বড় অ্যারেগুলির পক্ষে সত্যই খারাপ।
ডানকান সি

@ নিকগেনস এটি না, তাই না 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
    }
}

এখন, আপনি যদি Hashable নেই, কিন্তু আছে Equatable, আপনি এই পদ্ধতি ব্যবহার করতে পারেন:

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

শেষ অবধি, আপনি এর মতো স্বতন্ত্র সংস্করণের একটি মূল পথ সংস্করণ যুক্ত করতে পারেন:

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)সমাধান নিয়েছে। আপনি "চেক" এবং "সন্নিবেশ" সেট অপারেশনগুলিকে একসাথে একত্রিত করতে পারেন। স্ট্যাকওভারফ্লো.com
আলেকজান্ডার - মনিকা

ওহ, এটি চতুর :)
ডিনবম্বর্ন

14

Https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift দ্বারা অনুপ্রাণিত আমরা আরও একটি শক্তিশালী সরঞ্জাম ঘোষণা করতে পারি যা কোনও কীপ্যাথে ইউনিটির জন্য ফিল্টার করতে সক্ষম। জটিলতা সম্পর্কিত বিভিন্ন উত্তরের বিষয়ে আলেকজান্ডারের মন্তব্যে ধন্যবাদ, নীচের সমাধানগুলি সর্বোত্তম হওয়া উচিত be

অ-পরিবর্তনীয় সমাধান

আমরা এমন একটি ফাংশন দিয়ে প্রসারিত করি যা কোনও কীপথে ইউনিটির জন্য ফিল্টার করতে সক্ষম:

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

দ্রষ্টব্য: যে ক্ষেত্রে আপনার অবজেক্টটি রেঞ্জরেপসিয়েবল কালেকশনটির সাথে সামঞ্জস্য করে না, তবে সিকোয়েন্সের সাথে সামঞ্জস্য করে না, আপনার এই অতিরিক্ত এক্সটেনশন থাকতে পারে, তবে রিটার্নের ধরণটি সর্বদা অ্যারে হবে:

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

ব্যবহার

যদি আমরা নিজেরাই উপাদানগুলির জন্য ইউনিটিসিটি চাই, যেমন প্রশ্নে রয়েছে, আমরা কীপথটি ব্যবহার করি \.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}] */

মিউটেশন সমাধান

আমরা এমন কোনও মিউটেশন ফাংশন দিয়ে প্রসারিত করি যা যে কোনও কীপথে এককতার জন্য ফিল্টার করতে সক্ষম:

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

ব্যবহার

যদি আমরা নিজেরাই উপাদানগুলির জন্য ইউনিটিসিটি চাই, যেমন প্রশ্নে রয়েছে, আমরা কীপথটি ব্যবহার করি \.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
এখন এটি একটি ভাল বাস্তবায়ন! আমি কেবল সেই মূল পথটিই ক্লোজারে রূপান্তরিত হয়েছিলাম, যাতে আপনি উভয় স্বেচ্ছাসেবক কোড (ক্লোজারগুলিতে) এবং নিখুঁত সম্পত্তি চেহারা আপগুলি (কী পাথের মাধ্যমে) সমর্থন করতে ক্লোজার আরগ ব্যবহার করতে পারেন। আমি যে পরিবর্তনটি করব তা হ'ল keyPathডিফল্ট করা \.self, কারণ সম্ভবত এটিই বেশিরভাগ ব্যবহারের ক্ষেত্রে।
আলেকজান্ডার - মনিকা

1
@ আলেকজান্দার আমি সেলফের কাছে ডিফল্ট হওয়ার চেষ্টা করেছি, তবে তারপরে আমাকে Elementসর্বদা তৈরি করা দরকার Hashable। ডিফল্ট মানটির বিকল্প প্যারামিটার ছাড়াই একটি সাধারণ ওভারলোড যুক্ত করছে:extension Sequence where Element: Hashable { func unique() { ... } }
Cœur

আহ্ হ্যাঁ, বুদ্ধিমান!
আলেকজান্ডার - মনিকা পুনরায়

1
উজ্জ্বল ... সহজ এবং সর্বোত্তম 'নমনীয়'। ধন্যবাদ.
BonanzaDriver

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এবং অ্যারে সংযুক্তি ও (এন) এ চালিত হয়। যদিও এটির জন্য কেবল সমতুল্য প্রয়োজন, লাভযোগ্য নয় benefit
এয়ারস্পিডে গতিবেগ

এটি লেখার সত্যিই জটিল উপায় filter। এটি ও (এন ^ 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)এবং একটি আইকন দেয় যা নির্দেশ করে যে আইটেমটি wasোকানো হয়েছিল বা এটি ইতিমধ্যে সেটটিতে বিদ্যমান ছিল কিনা।

আইটেমটি সেটে থাকলে filterচূড়ান্ত ফলাফল থেকে বাদ দেবে।


1
পছন্দসই হতে হবে না তবে আপনি উপাদানগুলি যতবার সন্নিবেশ এবং সদস্যপদ পরীক্ষা করছেন তাই আপনার ও (এন) হিসাবেও তাদের ব্যয় গণনা করা উচিত। তবে এর অর্থ 3xO (এন) নয় কারণ এই হেগুলির এবং ফিল্টারটির সাথে সমান ব্যয় নেই তাই ও (এন) এর যোগটি কমলাগুলিতে আপেল। যদি আমরা সেট অপারেশনগুলি ফিল্টার ব্যয়ের একটি O (1) অংশ হিসাবে বিবেচনা করি, তবে জটিলতা কেবলমাত্র O (n), বৃহত্তর "O" সত্ত্বেও। এটিকে সীমাতে ঠেলাতে, উপাদানটি ইতিমধ্যে সেটে থাকলে আপনি সন্নিবেশগুলি এড়াতেও পারেন।
আলাইন টি।

আপনি ঠিক বলেছেন, deferকোডটি ব্যবহার করে দু'বার সেট টেস্ট অপারেশন করা হবে, একটিতে containsএবং অন্যটি দিয়ে insert। আরও পড়া সুইফ্ট ডকুমেন্টেশন, আমি দেখতে পেলাম যে insertউপাদানটি সন্নিবেশ করা হয়েছে কিনা তা নির্দেশ করে একটি টুপল দেয়, তাই আমি containsচেক অপসারণের কোডটি সহজ করেছি ।
এনেকো অ্যালোনসো

2
খুশী হলাম। আপনার এক্সটেনশানটি এটি করে সর্বোত্তম হতে পারেextension Sequence where Iterator.Element: Hashable { ... }
সিউর

@AlainT। নাঃ। উভয় insertএবং containsআছে O(1)জটিলতা। O(1) + O(1) = O(1)। এই দুটি অপারেশন এরপরে nবার হয়ে যায় (ক্লোজারের প্রতি একবার কল হয়ে যায় filter, যাকে উপাদান হিসাবে একবার বলা হয়) অর্থাত যদি কোনও ক্রিয়াকলাপ ইনপুট আকার নির্বিশেষে ধ্রুব পরিমাণ সময় নেয়, তবে এটি দু'বার করলেও স্থির সময় লাগে এটি ইনপুট আকার নির্বিশেষে। এর মোট জটিলতা হ'ল 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)) । মন্তব্যে উল্লিখিত হিসাবে, এটি শৃঙ্খলা সংরক্ষণ করে এবং এমন উপাদানগুলিতে কাজ করে যা হাস্যযোগ্য নয়।

তবে, @ অ্যালেন টি এর পদ্ধতিটিও অর্ডার সংরক্ষণ করে এবং এটি আরও দ্রুত। সুতরাং যদি না আপনার এলিমেন্টের ধরণটি হ্যাশযোগ্য না হয় বা আপনার কেবল একটি দ্রুত একটি লাইনার প্রয়োজন হয়, তবে আমি তাদের সমাধানটি নিয়ে যাওয়ার পরামর্শ দিই।

রিলিজ মোডে এক্সকোড 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 ইতিমধ্যে বর্তমান সংস্করণ রয়েছে।
ওড়ড্যাওয়ান

এটি একটি খুব মার্জিত সমাধান; দুর্ভাগ্যক্রমে, এটি বরং ধীর।
কলিন স্টার্ক

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

মানগুলি হ্যাশেবল করার জন্য আপনাকে বিরক্ত করার দরকার নেই এবং এটি আপনাকে স্বতন্ত্রতার জন্য ক্ষেত্রগুলির বিভিন্ন সংমিশ্রণ ব্যবহার করার অনুমতি দেয়।

দ্রষ্টব্য: আরও দৃ approach় পদ্ধতির জন্য, দয়া করে নীচের মন্তব্যে কোউরের প্রস্তাবিত সমাধানটি দেখুন।

stackoverflow.com/a/55684308/1033581

[Edit] সুইফট 4 বিকল্প

সুইফট ৪.২ এর সাহায্যে আপনি হ্যাশ বর্গটি আরও সহজ করে তৈরি করতে ব্যবহার করতে পারেন। উপরের এক্সটেনশনটি এটিকে উত্তোলনের জন্য পরিবর্তন করা যেতে পারে:

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 ব্যবহার করে এবং ignoring 0 উপেক্ষা করে) নিয়েও কাজ করবে।

peopleArray = peopleArray.filterDuplicate{ $1.name } 

এটি আচরণের উপর নির্ভর করে এলোমেলো ফলাফল দিতে পারে "\()", কারণ এটি আপনাকে যেমন মানা Hashableউচিত তেমন অনন্য মূল্য দেয় না । উদাহরণস্বরূপ, যদি আপনার উপাদানগুলি Printableসমস্ত একইরূপে ফিরে আসে descriptionতবে আপনার ফিল্টারিং ব্যর্থ হয়।
সিউর

একমত। ক্ষেত্রগুলির নির্বাচন (বা সূত্র) যা কাঙ্ক্ষিত স্বতন্ত্রতা প্যাটার্ন উত্পাদন করবে তা এটিকে বিবেচনায় নিতে হবে। অনেকগুলি ব্যবহারের ক্ষেত্রে, এটি একটি সাধারণ অ্যাডহক সমাধান সরবরাহ করে যার জন্য উপাদানটির শ্রেণি বা কাঠামোর কোনও পরিবর্তন দরকার নেই।
আলাইন টি।

2
@AlainT। সত্যিই এটি করবেন না। স্ট্রিংয়ের উদ্দেশ্য হ'ল কিছু ঘেটো অ্যাডহক কী প্রজন্মের প্রক্রিয়া নয়। Tসত্তা সীমাবদ্ধ Hashable
আলেকজান্ডার - মনিকা

@ আলেকজান্দার আমি এই ধারণাটি একটি নতুন উত্তরে প্রয়োগ করেছি: stackoverflow.com/a/55684308/1033581
Curur

আমি চাই ঠিক নিখুঁত উত্তর। তোমাকে অনেক ধন্যবাদ.
হার্ডিক ঠাক্কর

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]

"তারপরে আপনি যেমন চান তেমনই আপনার অ্যারে অর্ডার করতে পারেন" আমি যদি মূল অ্যারে থেকে একই ক্রম চাই তবে কী হবে? এটা এত সহজ না.
আলেকজান্ডার - মনিকা 21

3

ড্যানিয়েল ক্রমের সুইফট ২ টি উত্তরটির সামান্য আরও সংক্ষিপ্ত সিনট্যাক্স সংস্করণ , একটি ট্রেলিং ক্লোজার এবং শর্টহ্যান্ড আর্গুমেন্ট নাম ব্যবহার করে, যা আয়ারস্পিড বেলেসিটির মূল উত্তরের উপর ভিত্তি করে প্রদর্শিত হবে :

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প্রকারকে ফেরত দেয় ) ও হতে পারে rates

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পরিবর্তে ব্যবহার করুন। স্ট্যাকওভারফ্লো.com
আলেকজান্ডার - মনিকা পুনরায়

3

আপনার যদি মানগুলি বাছাই করা দরকার তবে এটি কাজ করে (সুইফ্ট 4)

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


2
আপনি এক্ষেত্রে উপাদানগুলির আদেশ হারিয়েছেন।
শিমিডট

মোটেও নয়, .sorted()শেষে এটিই for শুভেচ্ছা।
মৌরিসিও চিরিনো

@ মৌরিসিওচিরিনো এবং যদি আপনার মূল অ্যারেটি ছিল [2, 1, 1]? এটি বেরিয়ে আসবে [1, 2], এটির আদেশ দেওয়া হয়নি: পি
আলেকজান্ডার - মনিকা

2
@ মউরিসিওচিরিনো না, আমি নেই। উপাদানগুলি অনন্যভাবে প্রদর্শিত হয়েছে এমন ক্রম ধরে রাখার সময় যদি লক্ষ্যটি একটি ক্রম থেকে সদৃশ মানগুলি সরিয়ে ফেলা হয়, তবে এটি তা করে না। খুব পরিষ্কার পাল্টা উদাহরণ হ'ল [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

এখানে আমি বস্তুর জন্য কিছু ও (এন) সমাধান করেছি। কয়েকটি লাইনের সমাধান নয়, তবে ...

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:)] পেস্টবিন.com / w90pVe0p ( https://developer.apple.com/docamentation/… বাস্তবায়ন শেষ করবে this এটি কতটা সহজ তা পরীক্ষা করে দেখুন পেস্টবিন.com
আলেকজান্ডার - মনিকা পুনর্নির্ধারণ

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পরিবর্তে ব্যবহার করুন। স্ট্যাকওভারফ্লো.com
আলেকজান্ডার - মনিকা পুনরায়

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


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)

আমি মনে করি এটি সবচেয়ে সহজ
জ্যাক রস

এটি অর্ডার বজায় রাখে এবং আপনার
জ্যাক রুস


2
  1. প্রথমে এনএসঅর্ডার্ডসেটে অ্যারের সমস্ত উপাদান যুক্ত করুন।
  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

বিন্যাস ছাড়া ডুপ্লিকেটগুলির আউটপুট - [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

সবচেয়ে সহজ উপায় হ'ল এনএসআরডসেট ব্যবহার করা, যা অনন্য উপাদান সংরক্ষণ করে এবং উপাদানগুলির ক্রম সংরক্ষণ করে। ভালো লেগেছে:

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)

আমি আশ্চর্য হই যে এই পারফরম্যান্সটি কীভাবে এখানে আরও ভাল উত্তরের সাথে তুলনা করে। আপনি তুলনা করেছেন?
আলেকজান্ডার - মনিকা
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.