Xóa các phần tử trùng lặp khỏi một mảng trong Swift


252

Ngày nay trong Swift bạn chỉ cần gõ Set( yourArray ) để tạo một mảng duy nhất. (Hoặc một bộ được đặt hàng nếu cần.)

Trước khi điều đó là có thể, nó đã được thực hiện như thế nào?


Tôi có thể có một mảng trông như sau:

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

Hoặc, thực sự, bất kỳ chuỗi các phần giống như dữ liệu được gõ. Điều tôi muốn làm là đảm bảo rằng chỉ có một trong mỗi yếu tố giống hệt nhau. Ví dụ, mảng trên sẽ trở thành:

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

Lưu ý rằng các bản sao của 2, 6 và 15 đã bị xóa để đảm bảo rằng chỉ có một trong mỗi phần tử giống hệt nhau. Swift có cung cấp một cách để làm điều này một cách dễ dàng, hoặc tôi sẽ phải tự làm điều đó?


11
Cách dễ nhất là chuyển đổi mảng trong một NSSet, NSSet là một bộ sưu tập các đối tượng không có thứ tự, nếu cần giữ trật tự NSOrderedset.
Andrea

Bạn có thể sử dụng hàm giao nhau như bạn có thể tìm thấy trong lớp này với các hàm cho mảng: github.com/pNre/ExSwift/blob/master/ExSwift/Array.swift
Edwin Vermeer

Không phải là một phần của Swift nhưng tôi sử dụng Dollar. $.uniq(array) github.com/ankurp/Dollar#uniq---uniq
Andy

Có lẽ câu trả lời thanh lịch nhất, thông minh nhất và nhanh nhất được cung cấp bởi câu trả lời của mxcl dưới đây. Điều này cũng giúp duy trì trật tự
Mật ong

1
Tại sao bạn không sử dụng Settừ Swift? Bạn sẽ có thể cung cấp một danh sách các yếu tố độc đáo và không có thứ tự.
TibiaZ

Câu trả lời:


133

Bạn có thể tự cuộn, ví dụ như thế này ( được cập nhật cho Swift 1.2 với 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]

Phiên bản 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
}

Và như một phần mở rộng cho 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
Bạn cũng có thể triển khai phần thân của chức năng đó nhưvar addedDict = [T:Bool](); return filter(source) { addedDict(true, forKey: $0) == nil }
Airspeed Velocity

1
@AirspeedVelocity: Ý bạn là updateValue(true, forKey: $0)...thay vìaddedDict(true, forKey: $0)...
Jawwad

1
Rất tiếc, xin lỗi tôi vô tình phương pháp! Nên return filter(source) { addedDict.updateValue(true, forKey: $0) == nil }như bạn nói.
Vận tốc không khí

21
Chỉ cần một lời cảnh báo: Tránh thảo luận về hiệu suất cho các chức năng đơn giản như thế này cho đến khi bạn chắc chắn phụ thuộc vào hiệu suất của chúng, tại thời điểm đó, điều duy nhất bạn nên làm là điểm chuẩn. Tôi thường thấy mã không thể nhầm lẫn hoặc mã thậm chí ít hiệu suất hơn do đưa ra các giả định. :) Ngoài ra, điều này có lẽ dễ nắm bắt hơn:let uniques = Array(Set(vals))
Blixt

11
@Blixt Đồng ý. Một lần nữa, ở đây lợi thế nằm ở việc tôn trọng thứ tự các phần tử của mảng ban đầu.
Jean-Philippe Pellet

493

Bạn có thể chuyển đổi thành một tập hợp và trở lại một mảng khá dễ dàng:

let unique = Array(Set(originals))

Điều này không được đảm bảo để duy trì thứ tự ban đầu của mảng.


37
Có cách nào để sử dụng một tập hợp trong khi duy trì thứ tự ban đầu của mảng không?
Crashalot

6
@Crashalot Xem câu trả lời của tôi.
Jean-Philippe Pellet

5
Nếu bạn cần giữ các đối tượng duy nhất bởi một thuộc tính cụ thể, thì cũng nên thực hiện giao thức Hashable và Equitable trên lớp đó, thay vì chỉ sử dụng chuyển đổi Array-> Set-> Array
Fawkes

2
Đẹp!! Làm thế nào phức tạp thời gian của giải pháp này xin vui lòng?
JW.ZG 30/07/2016

2
Thất bại nếu các yếu tố trong originalskhông Hashable; chỉ Hashablecác loại dữ liệu có thể được thêm vào Tập hợp, nhưng bất kỳ loại dữ liệu nào cũng có thể được thêm vào một mảng.
Mecki

69

Nhiều câu trả lời có sẵn ở đây, nhưng tôi đã bỏ lỡ tiện ích mở rộng đơn giản này, phù hợp với Swift 2 trở lên:

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

Làm cho nó siêu đơn giản. Có thể được gọi như thế này:

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

Lọc dựa trên các thuộc tính

Để lọc một mảng dựa trên các thuộc tính, bạn có thể sử dụng phương pháp này:

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

Mà bạn có thể gọi như sau:

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

@Antoine Cảm ơn bạn đã Lọc dựa trên phần mở rộng thuộc tính. Nó thực sự hữu ích. Nhưng bạn có thể vui lòng giải thích làm thế nào nó hoạt động. Điều đó quá khó hiểu đối với tôi. Cảm ơn bạn
Mostafa Mohamed Raafat

Cập nhật cho swift 3: bộ lọc func Lặp lại (_ includeEuity: (_ lhs: Element, _ rhs: Element) -> Bool) -> [Element] {
cbartel

Phần đầu tiên của câu trả lời này ( extension Array where Element: Equatable) đang được thay thế bởi stackoverflow.com/a/36048862/1033581 cung cấp một giải pháp mạnh hơn ( extension Sequence where Iterator.Element: Equatable).
Cœur

7
Điều này sẽ có O(n²)hiệu suất thời gian, điều này thực sự tồi tệ cho các mảng lớn.
Duncan C

Bạn nên sử dụng một bộ để theo dõi các yếu tố được nhìn thấy cho đến nay, để mang lại O(n²)sự phức tạp khủng khiếp này trở lạiO(n)
Alexander - Tái lập Monica

63

Swift 3.0

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

1
hãy để uniqueOrderedNames = Array (NSOrderedset (mảng: userNames)) làm! [Chuỗi] nếu bạn có mảng Chuỗi, không phải là Bất kỳ
Zaporozhchenko Oleksandr

Thất bại nếu các yếu tố trong arraykhông Hashable; chỉ Hashablecác loại dữ liệu có thể được thêm vào Tập hợp, nhưng bất kỳ loại dữ liệu nào cũng có thể được thêm vào một mảng.
Mecki

Đã thử nghiệm trong Swift 5.1b5, với các yếu tố là Hashable và mong muốn duy trì trật tự, NSOrderedset (mảng: mảng) .array nhanh hơn một chút so với func swift uniqued () thuần túy bằng cách sử dụng một bộ lọc. Tôi đã thử nghiệm với 5100 chuỗi dẫn đến 13 giá trị duy nhất.
dlemex

62

Nếu bạn đặt cả hai phần mở rộng trong mã của mình, Hashablephiên bản nhanh hơn sẽ được sử dụng khi có thể và Equatablephiên bản sẽ được sử dụng làm dự phòng.

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

Nếu thứ tự không quan trọng, thì bạn luôn có thể sử dụng Bộ khởi tạo này .


được rồi, đã rõ. tôi không thể gọi nó bởi vì mảng của tôi là một mảng các cấu trúc ... tôi sẽ xử lý nó như thế nào trong trường hợp của tôi? cấu trúc của 20 biến, chuỗi và [chuỗi] khác nhau
David Seek

@David Seek Có vẻ như bạn chưa thực hiện được khả năng băm hoặc đánh đồng nghiêm ngặt của mình. Đúng không?
Jessy

1
@DavidSeek thích điều này, uniqueArray = nonUniqueArray.uniqueElements
Mert Celik

vâng đừng lo lắng. làm cho nó hoạt động ngay sau đó đã gần 2 năm rồi: P
David Seek

Điều này sẽ có O(n²)hiệu suất thời gian, điều này thực sự tồi tệ cho các mảng lớn.
Duncan C

44

chỉnh sửa / cập nhật Swift 4 trở lên

Chúng tôi cũng có thể mở rộng RangeReplaceableCollectiongiao thức để cho phép nó được sử dụng với StringProtocolcác loại:

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"

Phương pháp đột biến:

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

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

Đối với Swift 3 bấm vào đây


1
Tôi thích điều này, nó hoạt động với một loạt các từ điển quá!
DeyaEldeen

6
O (N ^ 2) là xấu :(
Alexander - Tái lập Monica

1
@Alexander Leo Dabus đã thay thế việc reducethực hiện, vì vậy bây giờ sự phức tạp đã khác.
Cœur

1
Kết quả thật thú vị. Đối với cả 1 triệu mục duy nhất và 8 triệu, phiên bản bộ lọc nhanh hơn. Tuy nhiên, phiên bản dựa trên bộ lọc mất 8,38 lần thời gian dài hơn cho 8 triệu vật phẩm duy nhất (một sợi tóc theo O(n)thời gian), trong đó phiên bản dựa trên bản đồ phẳng mất 7,47x dài hơn cho 8 triệu mục nhập duy nhất hơn 1 triệu, cho thấy phiên bản dựa trên bản đồ phẳng có tỷ lệ tốt hơn . Bằng cách nào đó phiên bản dựa trên bản đồ phẳng làm tốt hơn một chút so với O(n)thời gian!
Duncan C

1
Trong thực tế, khi tôi chạy thử nghiệm với nhiều mục hơn 64 lần trong mảng, phiên bản dựa trên sơ đồ phẳng sẽ nhanh hơn.
Duncan C

43

Swift 4

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

mọi nỗ lực insertcũng sẽ trả lại một tuple : (inserted: Bool, memberAfterInsert: Set.Element). Xem tài liệu .

Sử dụng giá trị trả về giúp chúng ta tránh lặp hoặc thực hiện bất kỳ thao tác nào khác.


7
Sau khi hồ sơ đơn giản, phương pháp này thực sự nhanh chóng. Nó nhanh hơn hàng trăm lần sau đó sử dụng giảm (_: _ :) hoặc thậm chí giảm (thành: _ :)
Kelvin

3
@Kelvin Bởi vì tất cả các thuật toán khác là O(n^2), và không ai nhận thấy.
Alexander - Tái lập Monica

@Kelvin câu trả lời này giống hệt với câu trả lời của Eneko Alonso + nhận xét của tôi (ngày 16 tháng 6 năm 17).
Cœur

27

Swift 4

Đảm bảo tiếp tục đặt hàng.

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

Tôi sử dụng ngay bây giờ, chỉ thay đổi tên phương thức để loại bỏ trùng lặp :)
J. Doe

Tôi đoán giải pháp này nhỏ gọn, nhưng tôi tin rằng giải pháp deanWombourne được đăng trước đó một năm có thể hiệu quả hơn một chút reduce: nói chung, đó chỉ là một dòng nữa trong toàn bộ dự án của bạn để viết chức năng của bạn là : var unique: [Iterator.Element] = []; for element in self where !unique.contains(element) { unique.append(element) }; return unique. Tôi thừa nhận tôi chưa thử nghiệm các màn trình diễn tương đối.
Cœur

3
Điều này sẽ có O(n²)hiệu suất thời gian, điều này thực sự tồi tệ cho các mảng lớn.
Duncan C

@NickGaens Không, không phải vậy O(n²). Không có gì nhanh chóng về điều này.
Alexander - Tái lập Monica

@ Cur reducehoặc reduce(into:)sẽ không tạo ra sự khác biệt quan trọng. Viết lại điều này để không liên tục gọi containssẽ tạo ra sự khác biệt lớn hơn nhiều.
Alexander - Tái lập Monica

16

Đây là một danh mục SequenceTypeđể duy trì thứ tự ban đầu của mảng, nhưng sử dụng một thao Settác containstra cứu để tránh O(n)chi phí cho contains(_:)phương thức của 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 }
    }
}

Nếu bạn không Hashable hoặc Equitable, bạn có thể vượt qua một vị từ để thực hiện kiểm tra tính bằng:

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

Bây giờ, nếu bạn không có Hashable, nhưng có thể tương đương, bạn có thể sử dụng phương pháp này:

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

Cuối cùng, bạn có thể thêm một phiên bản đường dẫn chính của duy nhất như thế này:

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

Bạn có thể dán cả hai thứ này vào ứng dụng của mình, Swift sẽ chọn đúng tùy thuộc vào Iterator.Elementloại trình tự của bạn .


Heyyy cuối cùng có người với một O(n)giải pháp. Nhân tiện, bạn có thể kết hợp các thao tác "kiểm tra" và "chèn" thành một. Xem stackoverflow.com/a/46354989/3141234
Alexander - Tái lập Monica

Ồ, thật thông minh :)
deanWombourne

14

Lấy cảm hứng từ https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift , chúng tôi có thể tuyên bố một công cụ mạnh hơn có thể lọc tính đơn nhất trên bất kỳ keyPath nào. Nhờ nhận xét của Alexander về các câu trả lời khác nhau về độ phức tạp, các giải pháp dưới đây sẽ gần tối ưu.

Giải pháp không đột biến

Chúng tôi mở rộng với một chức năng có thể lọc tính đơn nhất trên bất kỳ keyPath nào:

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

Lưu ý: trong trường hợp đối tượng của bạn không tuân thủ RangeReplacizableCollection, nhưng không tuân thủ Trình tự, bạn có thể có tiện ích mở rộng bổ sung này, nhưng kiểu trả về sẽ luôn là Mảng:

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

Sử dụng

Nếu chúng ta muốn duy nhất cho các thành phần, như trong câu hỏi, chúng ta sử dụng 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] */

Nếu chúng ta muốn duy nhất cho một cái gì đó khác (như cho idmột bộ sưu tập các đối tượng) thì chúng ta sử dụng keyPath theo lựa chọn của chúng ta:

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

Giải pháp đột biến

Chúng tôi mở rộng với chức năng đột biến có thể lọc tính đơn nhất trên bất kỳ keyPath nào:

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

Sử dụng

Nếu chúng ta muốn duy nhất cho các thành phần, như trong câu hỏi, chúng ta sử dụng 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] */

Nếu chúng ta muốn duy nhất cho một cái gì đó khác (như cho idmột bộ sưu tập các đối tượng) thì chúng ta sử dụng keyPath theo lựa chọn của chúng ta:

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
Bây giờ đó là một thực hiện tốt! Tôi chỉ với các đường dẫn chính đó là có thể chuyển đổi thành các bao đóng, để bạn có thể sử dụng một đối số bao đóng để hỗ trợ cả mã tùy ý (trong các bao đóng) và các tra cứu thuộc tính đơn thuần (thông qua các đường dẫn chính). Chỉ thay đổi tôi sẽ thực hiện là để keyPathmặc định \.self, bởi vì đó có thể là phần lớn các trường hợp sử dụng.
Alexander - Tái lập Monica

1
@Alexander Tôi đã cố gắng mặc định thành Tự, nhưng sau đó tôi sẽ cần phải Elementluôn luôn Hashable. Một thay thế cho một giá trị mặc định sẽ bổ sung một quá tải đơn giản không có tham số:extension Sequence where Element: Hashable { func unique() { ... } }
Cœur

À đúng rồi, có ý nghĩa!
Alexander - Tái lập Monica

1
Rực rỡ ... đơn giản và tốt nhất là 'linh hoạt'. Cám ơn.
BonanzaDriver

12

Một giải pháp thay thế (nếu không tối ưu) từ đây sử dụng các loại không thay đổi thay vì các biến:

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
}

Bao gồm để tương phản cách tiếp cận bắt buộc của Jean-Pillippe với một cách tiếp cận chức năng.

Là một phần thưởng, chức năng này hoạt động với các chuỗi cũng như các mảng!

Chỉnh sửa: Câu trả lời này được viết vào năm 2014 cho Swift 1.0 (trước đây Setđã có trong Swift). Nó không yêu cầu tuân thủ Hashable và chạy trong thời gian bậc hai.


8
Coi chừng, không có một, mà là hai cách này chạy trong thời gian bậc hai - cả hai containsvà mảng nối thêm chạy trong O (n). Mặc dù nó có lợi ích là chỉ yêu cầu công bằng, không thể băm.
Vận tốc không khí

đây là một cách thực sự phức tạp của văn bản filter. Đó là O (n ^ 2) (được yêu cầu nếu bạn không muốn yêu cầu Hashablesự phù hợp), nhưng ít nhất bạn nên gọi nó một cách rõ ràng
Alexander - Tái lập Monica

10

nhanh 2

với hàm uniq trả lời:

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

sử dụng:

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

Các Boolgiá trị rõ ràng là không cần thiết, như mã của bạn không bao giờ đọc nó. Sử dụng Setthay vì a Dictionaryvà bạn nhận được upvote của tôi.
Nikolai Ruhe

10

Trong Swift 5

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

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

Đầu ra sẽ là

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

2
Đây là sự lặp lại của nhiều câu trả lời đã có ở đây và nó không bảo toàn trật tự.
Alexander - Phục hồi lại

9

Thêm một giải pháp Swift 3.0 để loại bỏ các bản sao khỏi một mảng. Giải pháp này cải thiện trên nhiều giải pháp khác đã được đề xuất bởi:

  • Giữ nguyên thứ tự của các phần tử trong mảng đầu vào
  • Độ phức tạp tuyến tính O (n): bộ lọc thông đơn O (n) + bộ chèn O (1)

Cho mảng số nguyên:

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]

Mã chức năng:

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]

Mã mở rộng mảng:

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]

Mã này lợi dụng kết quả được trả về bởi insertthao tác trên Set, thực thi trên O(1)và trả về một tuple cho biết liệu mục đó đã được chèn hay nếu nó đã tồn tại trong tập hợp.

Nếu mục nằm trong tập hợp, filtersẽ loại trừ nó khỏi kết quả cuối cùng.


1
Không kén chọn nhưng bạn sẽ thực hiện thao tác chèn và kiểm tra thành viên nhiều lần vì có các yếu tố vì vậy bạn cũng nên tính chi phí của chúng là O (n). Tuy nhiên, điều này không có nghĩa là 3xO (n) vì các O này và không có chi phí bằng với bộ lọc nên việc thêm O (n) là táo vào cam. Nếu chúng tôi coi các hoạt động được đặt là một phần O (1) của chi phí bộ lọc, thì độ phức tạp chỉ là O (n), mặc dù có "O" lớn hơn. Đẩy điều này đến giới hạn, bạn cũng có thể tránh các phần chèn thêm khi phần tử đã có trong tập hợp.
Alain T.

Bạn đã đúng, sử dụng defermã sẽ thực hiện thao tác kiểm tra hai lần, một với containsvà một với insert. Đọc thêm tài liệu Swift, tôi thấy rằng inserttrả về một tuple cho biết phần tử có được chèn hay không, vì vậy tôi đã đơn giản hóa mã loại bỏ containskiểm tra.
Eneko Alonso

2
Đẹp. Phần mở rộng của bạn có thể được tối ưu bằng cách thực hiện nó trênextension Sequence where Iterator.Element: Hashable { ... }
Cœur

@ AlainT. Không. Cả hai insertcontainsO(1)sự phức tạp. O(1) + O(1) = O(1). Hai thao tác này sau đó được thực hiện nlần (một lần cho mỗi lần gọi đóng filter, được gọi một lần cho mỗi phần tử) Tức là nếu một thao tác mất một lượng thời gian không đổi bất kể kích thước đầu vào, thì thực hiện hai lần vẫn khiến nó mất thời gian không đổi đó là bất kể kích thước đầu vào. Tổng số phức tạp của điều này là O(n).
Alexander - Tái lập 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] }
  }
}

sử dụng:

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

hoặc là

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

Đây là O(n^2). Đừng làm điều này.
Alexander - Phục hồi Monica

8

Swift 5

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

Tôi đã thực hiện một số biến thể để tôi có thể chọn một khóa để so sánh. 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

Không cần sử dụng a Bool, khi giá trị duy nhất bạn sử dụng là true. Bạn đang tìm kiếm một "loại đơn vị" (một loại chỉ có một giá trị có thể). Loại đơn vị của Swift là Void, có giá trị duy nhất là ()(còn gọi là bộ dữ liệu trống). Vì vậy, bạn chỉ có thể sử dụng [T: Void]. Mặc dù bạn không nên làm điều đó, vì về cơ bản bạn chỉ mới phát minh ra Set. Sử dụng Setthay thế. Xem stackoverflow.com/a/55684308/3141234 Vui lòng xóa câu trả lời này.
Alexander - Phục hồi lại

8

Hãy suy nghĩ như một lập trình viên chức năng :)

Để lọc danh sách dựa trên việc phần tử đã xảy ra chưa, bạn cần chỉ mục. Bạn có thể sử dụng enumeratedđể lấy chỉ mục và maptrở về danh sách các giá trị.

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

Điều này đảm bảo trật tự. Nếu bạn không quan tâm đến thứ tự thì câu trả lời hiện tại Array(Set(myArray))đơn giản hơn và có thể hiệu quả hơn.


CẬP NHẬT: Một số lưu ý về hiệu quả và tính chính xác

Một vài người đã nhận xét về hiệu quả. Tôi chắc chắn trong trường viết mã chính xác và đơn giản trước và sau đó tìm ra các nút thắt sau đó, mặc dù tôi đánh giá cao việc tranh cãi liệu điều này có rõ ràng hơn không Array(Set(array)).

Phương pháp này chậm hơn rất nhiều Array(Set(array)). Như đã lưu ý trong các bình luận, nó bảo toàn trật tự và hoạt động trên các yếu tố không Hashable.

Tuy nhiên, phương pháp của @Alain T cũng giữ trật tự và cũng nhanh hơn rất nhiều. Vì vậy, trừ khi loại phần tử của bạn không thể băm được, hoặc bạn chỉ cần một lớp lót nhanh, thì tôi khuyên bạn nên đi với giải pháp của họ.

Dưới đây là một vài thử nghiệm trên MacBook Pro (2014) trên Xcode 11.3.1 (Swift 5.1) ở chế độ Phát hành.

Hàm profiler và hai phương thức để so sánh:

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

Và một loạt các đầu vào thử nghiệm:

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

Cung cấp như đầu ra:

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
Không giống như Array(Set(myArray)), điều này hoạt động cho những thứ không phảiHashable
Porter Child

1
... và không giống như Array(Set(myArray))thứ tự của mảng của bạn được duy trì.
Sander Saelmans

Có vẻ như câu trả lời tốt nhất cho tôi, ít nhất là ở thời điểm hiện tại khi Swift 5 đã là phiên bản hiện tại.
oradyvan

Đây là một giải pháp rất thanh lịch; Thật không may, nó cũng khá chậm.
Colin Stark

1
@TimMB Ôi tôi đọc nhầm bài của bạn. Tôi đã thấy sự thích nghi của ai đó lastIndex(of:). Tôi hoàn toàn không đồng ý với điểm rõ ràng và điểm tối ưu hóa trong trường hợp này. Tôi không nghĩ rằng việc thực hiện này đặc biệt rõ ràng, đặc biệt là so với một giải pháp dựa trên tập đơn giản. Trong mọi trường hợp, mã đó nên được trích xuất ra một hàm mở rộng. Thuật toán này về cơ bản trở nên không sử dụng được ngay cả ở kích thước đầu vào thấp, như trong hàng ngàn đến hàng chục nghìn. Không khó để tìm thấy các tập dữ liệu như vậy, mọi người có thể có hàng ngàn bài hát, tệp, danh bạ, v.v.
Alexander - Tái lập lại

6

Đối với các mảng trong đó các phần tử không phải là Hashable hay so sánh (ví dụ: các đối tượng phức tạp, từ điển hoặc cấu trúc), phần mở rộng này cung cấp một cách tổng quát để loại bỏ trùng lặp:

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

Bạn không phải bận tâm với việc tạo các giá trị Hashable và nó cho phép bạn sử dụng các kết hợp các trường khác nhau để duy nhất.

Lưu ý: để có cách tiếp cận mạnh mẽ hơn, vui lòng xem giải pháp do Coeur đề xuất trong các bình luận bên dưới.

stackoverflow.com/a/55684308/1033581

[EDIT] Swift 4 thay thế

Với Swift 4.2, bạn có thể sử dụng lớp Hasher để xây dựng hàm băm dễ dàng hơn nhiều. Phần mở rộng trên có thể được thay đổi để tận dụng điều này:

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

Cú pháp gọi hơi khác một chút vì bao đóng nhận được một tham số bổ sung có chứa hàm để băm một số lượng giá trị thay đổi (phải là Hashable riêng lẻ)

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

Nó cũng sẽ hoạt động với một giá trị duy nhất (sử dụng $ 1 và bỏ qua $ 0).

peopleArray = peopleArray.filterDuplicate{ $1.name } 

Điều này có thể cho kết quả ngẫu nhiên tùy thuộc vào hành vi của "\()", vì nó có thể không cung cấp cho bạn các giá trị duy nhất như tuân thủ Hashable. Ví dụ, nếu Printabletất cả các phần tử của bạn tuân theo cùng trả về description, thì quá trình lọc của bạn không thành công.
Cœur

Đã đồng ý. Lựa chọn các trường (hoặc công thức) sẽ tạo ra mẫu duy nhất mong muốn sẽ phải tính đến điều này. Đối với nhiều trường hợp sử dụng, điều này cung cấp một giải pháp đặc biệt đơn giản không yêu cầu thay đổi lớp hoặc cấu trúc của phần tử.
Alain T.

2
@ AlainT. Đừng làm điều này, thực sự. Mục đích của chuỗi không phải là một số cơ chế tạo khóa ghetto ad-hoc. Chỉ cần hạn chế Tđể được Hashable.
Alexander - Tái lập Monica

@Alexander Tôi đã áp dụng ý tưởng này trong một câu trả lời mới: stackoverflow.com/a/55684308/1033581
Cur

Câu trả lời hoàn hảo như tôi muốn. Cảm ơn bạn rất nhiều.
Hardik Thakkar

4

Bạn có thể sử dụng trực tiếp một bộ sưu tập để loại bỏ trùng lặp, sau đó chuyển nó trở lại một mảng

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]

Sau đó, bạn có thể đặt hàng mảng của bạn như bạn muốn

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

"Sau đó, bạn có thể đặt hàng mảng của mình như bạn muốn" Điều gì xảy ra nếu tôi muốn thứ tự giống như từ mảng ban đầu? Nó không dễ như thế đâu.
Alexander - Phục hồi Monica

3

Phiên bản cú pháp ngắn gọn hơn của câu trả lời Swift 2 của Daniel Krom , sử dụng tên đóng cửa và tên đối số tốc ký, dường như được dựa trên câu trả lời ban đầu của 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 }
}

Ví dụ về việc triển khai một loại tùy chỉnh có thể được sử dụng với uniq(_:)(phải phù hợp với Hashable, và do đó Equatable, vì Hashablemở rộng 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
  }

}

Trong đoạn mã trên ...

id, như được sử dụng trong quá tải ==, có thể là bất kỳ Equatableloại (hoặc phương thức nào trả về một Equatableloại, ví dụ someMethodThatReturnsAnEquatableType():). Mã nhận xét thể hiện việc mở rộng kiểm tra tính bằng, trong đó someOtherEquatablePropertymột thuộc tính khác của một Equatableloại (nhưng cũng có thể là một phương thức trả về một Equatableloại).

id, như được sử dụng trong thuộc hashValuetính được tính toán (bắt buộc phải tuân theo Hashable), có thể là bất kỳ thuộc tính Hashable(và do đó Equatable) (hoặc phương thức trả về mộtHashable loại).

Ví dụ về việc sử dụng 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

Không cần sử dụng a Bool, khi giá trị duy nhất bạn sử dụng là true. Bạn đang tìm kiếm một "loại đơn vị" (một loại chỉ có một giá trị có thể). Loại đơn vị của Swift là Void, có giá trị duy nhất là ()(còn gọi là bộ dữ liệu trống). Vì vậy, bạn chỉ có thể sử dụng [T: Void]. Mặc dù bạn không nên làm điều đó, vì về cơ bản bạn chỉ mới phát minh ra Set. Sử dụng Setthay thế. Xem stackoverflow.com/a/55684308/3141234
Alexander - Tái lập Monica

3

Trong trường hợp bạn cần các giá trị được sắp xếp, điều này hoạt động (Swift 4)

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


2
Bạn mất các yếu tố thứ tự trong trường hợp này.
Shmidt

Không hề, đó là những gì .sorted()cuối cùng là dành cho. Trân trọng.
Mauricio Chirino

@MauricioChirino Và nếu mảng ban đầu của bạn là [2, 1, 1]? Nó sẽ xuất hiện [1, 2], điều đó không được ra lệnh: p
Alexander - Tái lập Monica

2
@MaurermoChirino Không, tôi thì không. Nếu mục tiêu là loại bỏ các giá trị trùng lặp khỏi chuỗi, trong khi vẫn giữ thứ tự xuất hiện các phần tử duy nhất, thì điều này không làm được điều đó. Ví dụ truy cập rất rõ ràng là [2, 1, 1]. Sự xuất hiện đầu tiên của các yếu tố độc đáo, theo thứ tự là [2, 1]. Đó là câu trả lời đúng. Nhưng bằng cách sử dụng thuật toán (không chính xác) của bạn, bạn nhận được [1, 2], được sắp xếp, nhưng không theo thứ tự chính xác, nguyên bản.
Alexander - Tái lập Monica

2
Thất bại nếu các yếu tố trong arraykhông Hashable; chỉ Hashablecác loại dữ liệu có thể được thêm vào Tập hợp, nhưng bất kỳ loại dữ liệu nào cũng có thể được thêm vào một mảng.
Mecki

3

Đây là một giải pháp mà

  • Sử dụng không có NSloại di sản
  • Là hợp lý nhanh chóng với O(n)
  • Là súc tích
  • Giữ nguyên thứ tự
extension Array where Element: Hashable {

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

2

Ở đây tôi đã thực hiện một số giải pháp O (n) cho các đối tượng. Không phải giải pháp vài dòng, nhưng ...

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
Thay vì sử dụng một Settùy chỉnh DistinctWrapper, bạn nên sử dụng Dictionarytừ differAttribution cho các đối tượng. Khi bạn theo logic đó, cuối cùng bạn sẽ thực hiện [ Dictionary.init(_:uniquingKeysWith:)] pastebin.com/w90pVe0p(https://developer.apple.com/documentation/ , hiện được tích hợp vào thư viện chuẩn. Hãy xem cách đơn giản này pastebin.com/w90pVe0p
Alexander - Tái lập Monica

2

Tôi đã sử dụng câu trả lời của @ Jean-Philippe Pellet và thực hiện một phần mở rộng Array thực hiện các thao tác giống như thiết lập trên các mảng, trong khi vẫn duy trì thứ tự các phần tử.

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

Không cần sử dụng a Bool, khi giá trị duy nhất bạn sử dụng là true. Bạn đang tìm kiếm một "loại đơn vị" (một loại chỉ có một giá trị có thể). Loại đơn vị của Swift là Void, có giá trị duy nhất là ()(còn gọi là bộ dữ liệu trống). Vì vậy, bạn chỉ có thể sử dụng [T: Void]. Mặc dù bạn không nên làm điều đó, vì về cơ bản bạn chỉ mới phát minh ra Set. Sử dụng Setthay thế. Xem stackoverflow.com/a/55684308/3141234
Alexander - Tái lập Monica

2

Đây chỉ là một thực hiện rất đơn giản và thuận tiện. Một thuộc tính được tính toán trong phần mở rộng của Mảng có các phần tử tương đương.

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
Đây cũng là O(n^2).
Alexander - Tái lập Monica

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

Sử dụng:

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

Tôi nghĩ rằng đây là cách đơn giản nhất
Jack Rus

nó giữ trật tự và cung cấp cho bạn một mảng bạn muốn
Jack Rus

Đây cũng là O(n²).
Alexander - Tái lập Monica

2
  1. Đầu tiên, thêm tất cả các phần tử của một mảng vào NSOrderedset.
  2. Điều này sẽ loại bỏ tất cả các bản sao trong mảng của bạn.
  3. Một lần nữa chuyển đổi tập lệnh này thành một mảng.

Làm xong....

Thí dụ

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

đầu ra của mảngWithoutD repeatates - [1,2,4,6,8]


2

Một phiên bản rút gọn hoàn toàn dựa trên câu trả lời mở rộng mảng của @ 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)
        }
    }
}

Điều này thực hiện hai thao tác băm cho mỗi phần tử, không cần thiết. inserttrả về một tuple cho bạn biết phần tử đã ở đó hay đã được thêm lần đầu tiên. stackoverflow.com/a/55684308/3141234 Vui lòng xóa câu trả lời này.
Alexander - Phục hồi lại

1

Bạn luôn có thể sử dụng Từ điển, vì Từ điển chỉ có thể chứa các giá trị duy nhất. Ví dụ:

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

Như bạn có thể thấy, mảng kết quả sẽ không phải luôn luôn theo thứ tự '. Nếu bạn muốn sắp xếp / đặt hàng Array, hãy thêm cái này:

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

Cách dễ nhất là sử dụng NSOrderedset, lưu trữ các phần tử duy nhất và giữ nguyên thứ tự các phần tử. Giống:

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)

Tôi tự hỏi làm thế nào hiệu suất này so với các câu trả lời tốt hơn ở đây. Bạn đã so sánh chưa?
Alexander - Tái lập Monica
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.