Swift의 배열에서 중복 요소 제거


252

요즘 Swift에서는 간단히 입력 Set( yourArray )하여 배열을 고유하게 만듭니다. (또는 필요한 경우 주문 세트.)

그 전에는 어떻게 되었습니까?


다음과 같은 배열이있을 수 있습니다.

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

또는 실제로 같은 유형의 데이터 부분 시퀀스. 내가하고 싶은 것은 각각의 동일한 요소 중 하나만 있는지 확인하는 것입니다. 예를 들어 위의 배열은 다음과 같습니다.

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

2, 6 및 15의 복제본이 제거되어 동일한 각 요소 중 하나만 있음을 확인했습니다. Swift가이를 쉽게 수행 할 수있는 방법을 제공합니까, 아니면 직접해야합니까?


11
가장 쉬운 방법은에서 배열을 변환하는 것입니다 NSSet. NSSet은 NSOrderedSet 순서를 유지해야하는 경우 정렬되지 않은 객체 모음입니다.
Andrea

: 당신이 찾을 수있는 당신은 배열에 대한 기능이 클래스에서 교차 기능을 사용할 수 github.com/pNre/ExSwift/blob/master/ExSwift/Array.swift
에드윈 베르메르

Swift의 일부는 아니지만 Dollar를 사용합니다. $.uniq(array) github.com/ankurp/Dollar#uniq---uniq
Andy

아마도 가장 우아하고 똑똑하고 빠른 답변은 아래 mxcl의 답변을 통해 제공됩니다 . 또한 질서를 유지하는 데 도움이됩니다
Honey

1
SetSwift에서 사용하지 않습니까? 정렬되지 않은 고유 한 요소 목록을 제공 할 수 있습니다.
TibiaZ

답변:


133

예를 들어 다음과 같이 직접 롤백 할 수 있습니다 ( Swift 1.2에서 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]

스위프트 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
@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
@Blixt 동의합니다. 다시 한번, 여기서 장점은 원래 배열의 요소 순서에 관한 것입니다.
Jean-Philippe Pellet

493

집합으로 변환하고 다시 배열로 쉽게 다시 변환 할 수 있습니다.

let unique = Array(Set(originals))

어레이의 원래 순서를 유지한다고 보장 할 수는 없습니다.


37
배열의 원래 순서를 유지하면서 세트를 사용하는 방법이 있습니까?
Crashalot

6
@Crashalot 내 답변을 참조하십시오.
Jean-Philippe Pellet

5
당신이보다는 특정 속성에 의해 고유의 개체를 유지해야하는 경우도 그 클래스에 해쉬 및 Equatable 프로토콜을 구현하는 대신 단지 Array-> 세트 -> 배열 변환 사용
폭스

2
좋은!! 이 솔루션의 시간 복잡성은 무엇입니까?
JW.ZG

2
의 요소 originals가 아닌 경우 실패합니다 Hashable. Hashable데이터 유형 만 세트에 추가 할 수 있지만 모든 데이터 유형은 배열에 추가 할 수 있습니다.
Mecki

69

여기에 많은 답변이 있지만 Swift 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 }

@Antoine 속성 확장을 기반으로 한 필터링에 감사합니다. 정말 유용합니다. 그러나 어떻게 작동하는지 설명해 주시겠습니까? 나를 이해하기가 너무 어렵습니다. 감사합니다
Mostafa Mohamed Raafat

신속한 3에 대한 업데이트 : func filterDuplicates (_ includeElement : (_lhs : Element, _ rhs : Element)-> Bool)-> [Element] {
cbartel

이 답변의 첫 번째 부분 ( extension Array where Element: Equatable)은 보다 강력한 솔루션 ( ) 을 제공하는 stackoverflow.com/a/36048862/1033581 로 대체되었습니다 extension Sequence where Iterator.Element: Equatable.
Cœur

7
이것은 O(n²)시간 성능을 가지게되는데, 이는 큰 어레이에는 실제로 좋지 않습니다.
Duncan C

이 끔찍한 O(n²)복잡성을 되돌려 놓으려면 지금까지 본 요소를 추적하기 위해 세트를 사용해야합니다.O(n)
Alexander-Reinstate Monica

63

스위프트 3.0

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

1
uniqueOrderedNames = Array (NSOrderedSet (array : userNames))를 다음과 같이 설정하십시오! [문자열] u는 스트링의 배열이 아닌 경우 어느
Zaporozhchenko 올렉산드르

의 요소 array가 아닌 경우 실패합니다 Hashable. Hashable데이터 유형 만 세트에 추가 할 수 있지만 모든 데이터 유형은 배열에 추가 할 수 있습니다.
Mecki

요소가 해시 가능하고 순서를 유지하기를 원한다면 Swift 5.1b5에서 테스트 한 NSOrderedSet (array : array) .array는 필터가있는 세트를 사용하는 순수한 swift func uniqued ()보다 약간 빠릅니다. 나는 5100 개의 문자열로 테스트하여 13 개의 고유 값을 얻었습니다.
dlemex 19

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

순서가 중요하지 않은 경우 항상 이 Set initializer 만 사용할 수 있습니다 .


알았어 내 배열이 구조체의 배열이기 때문에 호출 할 수 없었습니다 ... 내 경우에는 어떻게 처리합니까? 20 개 개의 변수 문자열과 [캐릭터]의 구조체
다윗 탐색

@David Seek 엄격한 해시 가능 또는 동일성을 만들지 않은 것 같습니다. 그 맞습니까?
Jessy

1
@DavidSeek like this, uniqueArray = nonUniqueArray.uniqueElements
Mert Celik

그래 걱정 하지마 바로 작동합니다. 지금은 약 2 년이 : P
다윗은 탐색

이것은 O(n²)시간 성능을 가지게되는데, 이는 큰 어레이에는 실제로 좋지 않습니다.
Duncan C

44

Swift 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
나는 이것을 좋아합니다. 사전 배열에서도 작동합니다!
DeyaEldeen

6
O (N ^ 2)는 나쁘다 :(
Alexander-Reinstate Monica

1
@Alexander Leo Dabus가 reduce구현 을 대체 했으므로 이제는 복잡성이 다릅니다.
Cœur

1
결과는 흥미 롭습니다. 100 만 개의 고유 항목과 8 백만 개의 필터 버전이 더 빠릅니다. 그러나 필터 기반 버전은 8 백만 개의 고유 항목 ( O(n)시간이 지남에 따라 머리카락 )에 대해 8.38 배 더 오래 걸리며, 플랫 맵 기반 버전은 1 백만이 아닌 8 백만 개의 고유 항목에 대해 7.47 배 더 오래 걸리므로 플랫 맵 기반 버전의 확장 성이 더 좋습니다. . 어떻게 든 플랫 맵 기반 버전이 O(n)시간 보다 약간 나아 집니다!
Duncan C

1
실제로 배열에서 64 배 더 많은 항목으로 테스트를 실행하면 플랫 맵 기반 버전이 더 빠릅니다.
Duncan C

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
간단한 프로파일 링 후이 방법은 정말 빠릅니다. reduce (_ : _ :) 또는 심지어 reduce (_ :)를 사용하는 것보다 수백 배 더 빠릅니다.
Kelvin

3
@Kelvin 다른 알고리즘은 모두 있었으므로 O(n^2)아무도 눈치 채지 못했습니다.
Alexander-Reinstate Monica

@Kelvin이 답변은 Eneko Alonso 답변 + 내 의견 (Jun 16 '17) 과 동일합니다 .
Cœur

27

스위프트 4

주문을 계속 보장합니다.

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

나는 이것을 지금 사용하고 메소드 이름을 removeDuplicates :)로 변경했다.
J. Doe

나는이 솔루션은 컴팩트 생각,하지만 난 믿고 deanWombourne 솔루션은 전년있을 수 있습니다 게시 약간 더 효율적인 (A)보다 reduce: 전체, 그것은 귀하의 기능을 작성하는 전체 프로젝트의 또 하나 개의 라인이다 : var unique: [Iterator.Element] = []; for element in self where !unique.contains(element) { unique.append(element) }; return unique. 나는 아직 상대 성능을 테스트하지 않았다는 것을 인정합니다.
Cœur

3
이것은 O(n²)시간 성능을 가지게되는데, 이는 큰 어레이에는 실제로 좋지 않습니다.
Duncan C

@NickGaens 아니, 아니에요 O(n²). 이것에 대해 빠른 것은 없습니다.
Alexander-Reinstate Monica

@C –ur reduce또는 reduce(into:)중요한 차이를 만들지 않을 것입니다. 이것을 반복해서 호출하지 않도록 다시 contains쓰면 훨씬 더 큰 차이를 만들 수 있습니다.
Alexander-Reinstate Monica

16

다음 SequenceType은 배열의 원래 순서를 유지하지만 a Set를 사용하여 배열 방법 containsO(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 }
    }
}

Hashable 또는 Equatable이 아닌 경우 동등성 검사를 수행하기 위해 술어를 전달할 수 있습니다.

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

당신이 해쉬을 가지고 있지만하지 않는 경우 이제 있습니다 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] }
    }
}

이 두 가지를 앱에 붙일 수 있으며 Swift는 시퀀스 Iterator.Element유형 에 따라 올바른 것을 선택합니다 .


Heyyy는 마침내 O(n)해결책을 가진 사람입니다 . "check"및 "insert"세트 조작을 하나로 결합 할 수 있습니다. stackoverflow.com/a/46354989/3141234
Alexander-Reinstate Monica

오, 그것은 영리합니다 :)
deanWombourne

14

https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-swift에서 영감을 받음 에서 모든 keyPath에서 단일성을 필터링 할 수있는보다 강력한 도구를 선언 할 수 있습니다. 복잡성에 대한 다양한 답변에 대한 Alexander의 의견 덕분에 아래 솔루션은 거의 최적이어야합니다.

비 돌연변이 솔루션

모든 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을 준수하지 않지만 Sequence를 준수하는 경우이 추가 확장명을 사용할 수 있지만 반환 유형은 항상 배열입니다.

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객체 (예 : 객체 모음)에 대해 단일성을 원하면 선택한 keyPath를 사용합니다.

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객체 (예 : 객체 모음)에 대해 단일성을 원하면 선택한 keyPath를 사용합니다.

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
@Alexander 나는 기본값을 Self로 설정하려고했지만 Element항상 만들어야 합니다 Hashable. 기본값에 대한 대안은 매개 변수없이 간단한 과부하를 추가하는 것입니다.extension Sequence where Element: Hashable { func unique() { ... } }
Cœur

아 그렇습니다.
알렉산더-복원 모니카

1
훌륭합니다 ... 단순하고 모든 '유연한'. 고마워.
BonanzaDriver 2018 년

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
}

Jean-Pillippe의 명령 방식과 기능적 접근법을 대조하기 위해 포함되었습니다.

보너스 로이 기능은 문자열뿐만 아니라 배열에서도 작동합니다!

편집 : 이 답변은 2014 년 Swift 1.0 용으로 작성되었습니다 (Swift Set에서 사용 가능). Hashable 준수가 필요하지 않으며 2 차 시간에 실행됩니다.


8
이것은 이차 시간에 실행되는 방법이 하나도 없지만 두 가지 방법이 있습니다. 둘 다 contains및 배열 추가는 O (n)로 실행됩니다. 비록 해시 블이 아닌 동일성 만 필요로하는 이점이 있지만.
속도 속도

이것은 정말로 복잡한 글쓰기 방법입니다 filter. 그것은 O (n ^ 2) ( Hashable적합성 을 요구하지 않으려면 필요함 )이지만 최소한 명시 적으로 호출해야합니다
Alexander-Reinstate Monica

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대신 a 를 사용 Dictionary하면 내 공감대를 얻습니다.
Nikolai Ruhe

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

어레이에서 중복을 제거하는 Swift 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]

이 코드는 inserton 에 대한 오퍼레이션에 의해 리턴 된 결과를 이용합니다 Set.O(1) 항목이 삽입되었는지 또는 세트에 이미 존재하는지 여부를 나타내는 튜플을 리턴합니다.

항목이 세트에 있으면 filter최종 결과에서 제외됩니다.


1
까다 롭지는 않지만 요소가있는 횟수만큼 삽입 및 멤버쉽 테스트를 수행하므로 비용도 O (n)으로 계산해야합니다. 그러나 이것은 3xO (n)을 의미하지는 않지만 이러한 O와 필터와 동일한 비용이 없으므로 O (n)의 추가는 오렌지에 사과입니다. 우리가 set 연산을 필터 비용의 O (1) 부분으로 생각한다면 복잡도는 단지 O (n)이지만 더 큰 "O"를 갖습니다. 이것을 한계까지 밀어 넣으면 요소가 이미 세트에있을 때 삽입을 피할 수 있습니다.
Alain T.

다음을 사용하여, 맞아 defer, 두 번 설정 테스트 작업을 할 것입니다 하나의 코드 contains와 하나를 insert. Swift 문서를 더 읽으면 insert요소가 삽입되었는지 여부를 나타내는 튜플 을 반환 한다는 것을 알았 으므로 contains검사를 제거하는 코드를 단순화했습니다 .
Eneko Alonso

2
좋은. Cextension Sequence where Iterator.Element: Hashable { ... }
ur

@AlainT. 아니. 모두 insertcontainsO(1)복잡성을. O(1) + O(1) = O(1). 그런 다음이 두 작업이 완료 n됩니다 (요소 당 한 번 호출되는 클로저 호출 당 filter한 번) 즉, 작업이 입력 크기에 관계없이 일정한 시간이 걸리면 두 번 수행하면 여전히 일정한 시간이 걸립니다 입력 크기에 관계없이 이것의 총 복잡성은입니다 O(n).
Alexander-Reinstate Monica

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). 이러지 마
Alexander-Reinstate Monica

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 } } }
Marcelo de Aguiar

사용하는 Bool유일한 값이이면 을 사용할 필요가 없습니다 true. "유니트 유형"(하나의 가능한 값만있는 유형)에 도달했습니다. Swift의 단위 유형은 ( Void값은 ()빈 튜플)입니다. 그래서 당신은 사용할 수 있습니다 [T: Void]. 기본적으로 방금 발명했기 때문에 그렇게해서는 안됩니다 Set. Set대신 사용하십시오 . stackoverflow.com/a/55684308/3141234를 참조하십시오 .이 답변을 삭제하십시오.
Alexander-복직 모니카

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 (Swift 5.1)에서 MacBook Pro (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
Porter Child

1
... Array(Set(myArray))배열 순서 와 달리 유지됩니다.
샌더 Saelmans

Swift 5가 이미 현재 버전 일 때 적어도 현재로서는 나에게 가장 좋은 대답처럼 보입니다.
oradyvan

이것은 매우 우아한 솔루션입니다. 불행히도, 그것은 또한 느리다.
콜린 스타크

1
@ Timm 오 게시물을 잘못 읽었습니다. 나는을 사용한 누군가의 적응을 보았다 lastIndex(of:). 이 경우 명확성 대 최적화 지점에 대해 완전히 동의하지 않습니다. 특히 간단한 세트 기반 솔루션과 비교할 때이 구현이 명확하지 않다고 생각합니다. 어쨌든 그러한 코드는 확장 기능으로 추출해야합니다. 이 알고리즘은 기본적으로 수천에서 수만에 이르는 낮은 입력 크기에서도 사용할 수 없게됩니다. 그러한 데이터 세트를 찾는 것은 어렵지 않습니다. 사람들은 수천 곡의 노래, 파일, 연락처 등을 가질 수 있습니다.
Alexander-Reinstate Monica

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에서는 Hasher 클래스를 사용하여 해시를 훨씬 쉽게 만들 수 있습니다. 위의 확장은 이것을 활용하도록 변경 될 수 있습니다.

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가 모두 same을 반환하여 준수 description하면 필터링이 실패합니다.
Cœur

동의했다. 원하는 고유성 패턴을 생성 할 필드 (또는 수식)를 선택하면이를 고려해야합니다. 많은 유스 케이스에서 이것은 요소의 클래스 나 구조체를 변경할 필요가없는 간단한 임시 솔루션을 제공합니다.
Alain T.

2
@AlainT. 진짜 이러지 마 문자열의 목적은 빈민가 임시 키 생성 메커니즘이 아닙니다. 그냥 제한 T되 고 Hashable.
Alexander-Reinstate Monica

@Alexander 나는이 아이디어를 새로운 답변으로 적용했습니다 : stackoverflow.com/a/55684308/1033581
Cœur

내가 원하는 완벽한 답변. 정말 고맙습니다.
Hardik Thakkar 2016 년

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]

"그런 다음 원하는대로 배열을 주문할 수 있습니다"원래 배열과 동일한 순서를 원하면 어떻게합니까? 그렇게 쉬운 일이 아닙니다.
Alexander-Reinstate Monica

3

Airspeed Velocity의 원래 답변을 기반으로 표시되는 후행 폐쇄 및 속기 인수 이름을 사용하여 Daniel Krom의 Swift 2 answer의 간결한 구문 버전이 약간 간결 해졌습니다 .

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()). 주석 처리 된 코드 someOtherEquatablePropertyEquatable유형 의 또 다른 속성 인 유형 동등성을 검사 하는 방법을 보여줍니다 ( 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. "유니트 유형"(하나의 가능한 값만있는 유형)에 도달했습니다. Swift의 단위 유형은 ( Void값은 ()빈 튜플)입니다. 그래서 당신은 사용할 수 있습니다 [T: Void]. 기본적으로 방금 발명했기 때문에 그렇게해서는 안됩니다 Set. Set대신 사용하십시오 . 12
Alexander-Reinstate Monica

3

정렬 된 값이 필요한 경우 작동합니다 (Swift 4)

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


2
이 경우 요소 순서를 잃어버린 것입니다.
Shmidt

전혀, 그것이 .sorted()결국의 목적입니다. 문안 인사.
Mauricio Chirino

@MauricioChirino 그리고 원래 배열이라면 [2, 1, 1]? 그것은 나올 것이다 [1, 2], 그것은 주문되지 않았다 : p
Alexander-Reinstate Monica

2
@MauricioChirino 아니, 아니에요. 요소가 고유하게 나타난 순서를 유지하면서 시퀀스에서 중복 값을 제거하는 것이 목표라면 그렇게하지 않습니다. 매우 명확한 카운터 예는 [2, 1, 1]입니다. 고유 한 요소의 첫 등장은 순서대로입니다 [2, 1]. 정답입니다. 하지만 당신의 (잘못된) 알고리즘을 사용하여, 당신은 얻을 수 [1, 2]있는 되어 분류되어 있지만 아닌 올바른, 원래의 순서.
Alexander-Reinstate Monica

2
의 요소 array가 아닌 경우 실패합니다 Hashable. Hashable데이터 유형 만 세트에 추가 할 수 있지만 모든 데이터 유형은 배열에 추가 할 수 있습니다.
Mecki

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
Setcustom과 함께를 사용하는 대신 from distinctAttributes를 객체로 DistinctWrapper사용해야 Dictionary합니다. 이 논리를 따르면 결국 표준 라이브러리에 내장 된 [ Dictionary.init(_:uniquingKeysWith:)] pastebin.com/w90pVe0p(https://developer.apple.com/documentation/…을 구현 하게됩니다. 이것이 얼마나 간단한 지 확인하십시오 pastebin.com/w90pVe0p
Alexander-Reinstate Monica

2

@ Jean-Philippe Pellet의 대답을 사용하고 요소 순서를 유지하면서 배열에서 집합과 같은 작업을 수행하는 Array 확장을 만들었습니다.

/// 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. "유니트 유형"(하나의 가능한 값만있는 유형)에 도달했습니다. Swift의 단위 유형은 ( Void값은 ()빈 튜플)입니다. 그래서 당신은 사용할 수 있습니다 [T: Void]. 기본적으로 방금 발명했기 때문에 그렇게해서는 안됩니다 Set. Set대신 사용하십시오 . 12
Alexander-Reinstate Monica

2

이것은 매우 간단하고 편리한 구현입니다. 동일한 요소가있는 Array 확장에서 계산 된 속성입니다.

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)입니다.
Alexander-Reinstate Monica

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

용법:

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

나는 이것이 가장 간단하다고 생각합니다
Jack Rus

이 순서를 유지하고 당신이 원하는 배열을 제공합니다
잭 루스

이것 또한 O(n²)입니다.
Alexander-Reinstate Monica

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

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

이것은 요소 당 두 가지 해싱 작업을 수행하므로 불필요합니다. 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)

이 성능이 여기에 더 나은 답변과 어떻게 비교되는지 궁금합니다. 비교 했습니까?
Alexander-Reinstate Monica
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.