web-dev-qa-db-ja.com

Swiftで配列から重複した要素を削除する

次のような配列があります。

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

あるいは、実際には、データの同じタイプの部分のシーケンスです。私がやりたいことは、それぞれ同じ要素が1つだけあることを確認することです。たとえば、上記の配列は次のようになります。

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

2、6、および15の重複は、各同一要素が1つだけであることを確認するために削除されています。 Swiftはこれを簡単に行う方法を提供しますか、それとも私は自分でやらなければなりませんか?

199
Altair357

あなたはあなた自身のものを転がすことができます。このように(を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]

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

あなたはセットに変換し、再びアレイに戻すことが非常に簡単にできます:

let unique = Array(Set(originals))

これは、配列の元の順序を維持することを保証するものではありません。

410
Ben Packard

ここにはたくさんの答えがありますが、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 }
59
Antoine

これはこのページにすでにある良い情報のいくつかを取り、可能ならばHashable/Setアプローチを適用し、そうでなければEquatableコードにフォールバックします。

Swift 4でEquatable拡張子が変更されました(Hashableは変わりません)

public extension Sequence where Element: Equatable {
  var uniqueElements: [Element] {
    return self.reduce(into: []) {
      uniqueElements, element in

      if !uniqueElements.contains(element) {
        uniqueElements.append(element)
      }
    }
  }
}

Swift 3

public extension Sequence where Iterator.Element: Hashable {
    var uniqueElements: [Iterator.Element] {
        return Array( Set(self) )
    }
}
public extension Sequence where Iterator.Element: Equatable {
    var uniqueElements: [Iterator.Element] {
        return self.reduce([]){
            uniqueElements, element in

            uniqueElements.contains(element)
            ? uniqueElements
            : uniqueElements + [element]
        }
    }
}

Swift 2

public extension SequenceType where Generator.Element: Hashable {
  var uniqueElements: [Generator.Element] {
    return Array(
      Set(self)
    )
  }
}
public extension SequenceType where Generator.Element: Equatable {
  var uniqueElements: [Generator.Element] {
    return self.reduce([]){uniqueElements, element in
      uniqueElements.contains(element)
        ? uniqueElements
        : uniqueElements + [element]
    }
  }
}
52
Jessy

スイフト3.0

let uniqueUnordered = Array(Set(array))
let uniqueOrdered = Array(NSOrderedSet(array: array))
47
Jovan Stankovic

編集/更新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"

Swift 3クリック はこちら

37
Leo Dabus

スイフト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)も返されます。 のドキュメント をご覧ください。

戻り値を使用することで、ループしたり他の操作をしたりすることを回避できます。

26
mxcl

Swift 4

注文を続けることが保証されています。

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

ここで から 変数ではなく不変型を使った(最適ではないにしても)代替の解決策:

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が利用可能になる前)。それはハッシュ可能な適合性を必要とせず、二次時間で実行されます。

12
Pliskin

これは配列の元の順序を保持するSequenceTypeのカテゴリですが、Setを使用してcontains検索を実行し、ArrayのO(n)メソッドのcontains(_:)コストを回避します。

public extension Array where Element: Hashable {

    /// Return the array 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.
    public func uniqued() -> [Element] {
        var seen = Set<Element>()
        return self.filter { seen.insert($0).inserted }
    }
}

もしあなたがHashableを持っていないなら、あなたはこれをすることができる:

public extension Sequence where Iterator.Element: Equatable {

    public func uniqued() -> [Iterator.Element] {
        var buffer: [Iterator.Element] = []

        for element in self {
            guard !buffer.contains(element) else { continue }

            buffer.append(element)
        }

        return buffer
    }
}

あなたはこれらの両方をあなたのアプリに固執することができます、SwiftはあなたのシーケンスのIterator.Elementタイプに応じて正しいものを選びます。

12
deanWombourne

スイフト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
10
Daniel Krom

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

使用法:

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

または

["Ljubljana", "London", "Los Angeles", "Ljubljana"].uniqueOrdered()
9
Rok Gregorič

配列から重複を削除するためのもう1つの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]

このコードは、O(1)上で実行されるinsertに対するSet操作によって返された結果を利用し、項目が挿入されたのか、それともすでにセット内に存在したのかを示すTupleを返します。

アイテムがセット内にある場合、filterはそのアイテムを最終結果から除外します。

6
Eneko Alonso

Setコレクションを直接使って重複を取り除き、それを配列にキャストバックすることができます。

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

要素がHashableでもComparableでもない配列(複雑なオブジェクト、辞書、構造体など)の場合、この拡張機能は重複を削除するための一般的な方法を提供します。

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

値をHashableにすることに煩わされる必要はなく、一意性のためにフィールドのさまざまな組み合わせを使用することができます。

注:より堅牢なアプローチについては、以下のコメントでCoeurによって提案された解決策を参照してください。

stackoverflow.com/a/55684308/1033581

[編集]Swift 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}     
    }
}

クロージャーが可変数の値をハッシュするための関数を含む追加のパラメーター(個別にHashableでなければならない)を受け取るため、呼び出し構文は少し異なります。

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

単一の一意性の値($ 1を使用し、$ 0を無視する)でも機能します。

peopleArray = peopleArray.filterDuplicate{ $1.name } 
5
Alain T.

https://www.swiftbysundell.com/posts/the-power-of-key-paths-in-Swift に触発され、我々は宣言することができます任意のkeyPathでの統一性をフィルタリングできる、より強力なツール。 Alexanderが複雑さに関するさまざまな回答についてコメントしていることから、以下の解決策はほぼ最適なはずです。

非変異ソリューション

どのkeyPathでも単一性をフィルタリングできる関数で拡張します。

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}] */
5
Cœur

Swift 4.2テスト済み

extension Sequence where Iterator.Element: Hashable {
    func unique() -> [Iterator.Element] {
        var seen: [Iterator.Element: Bool] = [:]
        return self.filter { seen.updateValue(true, forKey: $0) == nil }
    }
}
4
blackjacx

Daniel KromのSwift 2 answer のやや簡潔な構文バージョン。末尾のクロージャと短縮形の引数名を使用します。これは 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 }
}

uniq(_:)で使用できるカスタム型の実装例(HashableEquatableを拡張するため、これは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
3
Scott Gardner
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)
3
Jack Rus

ここで私はオブジェクトのための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")
2
kas-kad

これは非常に単純で便利な実装です。等化可能要素を持つ、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
    }
}
2
DaveAMoore

辞書は一意の値しか保持できないため、いつでも辞書を使用できます。例えば:

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

2
AT3D

私は@ 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) })
  }
}
2
Will Richardson

値をソートする必要がある場合、これは機能します(Swift 4)

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

2
  1. 最初に、配列のすべての要素をNSOrderedSetに追加します。
  2. これにより、アレイ内の重複がすべて削除されます。
  3. 再度、このorderedsetを配列に変換します。

完了....

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

Scott Gardnerの答え に似た答えを提案してみましょう。このソリューションは、カスタムオブジェクトの配列から重複を削除します(初期の順序を維持します)。

// Custom Struct. Can be also class. 
// Need to be `equitable` in order to use `contains` method below
struct CustomStruct : Equatable {
      let name: String
      let lastName : String
    }

// conform to Equatable protocol. feel free to change the logic of "equality"
func ==(lhs: CustomStruct, rhs: CustomStruct) -> Bool {
  return (lhs.name == rhs.name && lhs.lastName == rhs.lastName)
}

let categories = [CustomStruct(name: "name1", lastName: "lastName1"),
                  CustomStruct(name: "name2", lastName: "lastName1"),
                  CustomStruct(name: "name1", lastName: "lastName1")]
print(categories.count) // prints 3

// remove duplicates (and keep initial order of elements)
let uniq1 : [CustomStruct] = categories.reduce([]) { $0.contains($1) ? $0 : $0 + [$1] }
print(uniq1.count) // prints 2 - third element has removed

そして、あなたがこのreduceマジックがどのように機能するのか疑問に思っているのであれば - これは全く同じですが、より拡張されたreduce構文を使うことです。

let uniq2 : [CustomStruct] = categories.reduce([]) { (result, category) in
  var newResult = result
  if (newResult.contains(category)) {}
  else {
    newResult.append(category)
  }
  return newResult
}
uniq2.count // prints 2 - third element has removed

このコードをSwift Playgroundにコピーアンドペーストして遊べます。

1
n0_quarter

これはSwift 4.2以降で最も単純な方法です。

let keyarray:NSMutableArray = NSMutableArray()

for  object in dataArr
{
    if !keysArray.contains(object){
        keysArray.add(object)
    }
}

print(keysArray)
1
Deepak Yadeedya

Swift 3.0では、順序を保ちながら、重複した要素を排除することが最も簡単で最速のソリューションです。

extension Array where Element:Hashable {
    var unique: [Element] {
        var set = Set<Element>() //the unique list kept in a Set for fast retrieval
        var arrayOrdered = [Element]() //keeping the unique list of elements but ordered
        for value in self {
            if !set.contains(value) {
                set.insert(value)
                arrayOrdered.append(value)
            }
        }

        return arrayOrdered
    }
}
1
Ciprian Rarau

Xcode 10.1 - Swift 4.2シンプルでパワフルなソリューション

func removeDuplicates(_ nums: inout [Int]) -> Int {
    nums = Set(nums).sorted()
    return nums.count
}

var arr = [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9]
removeDuplicates(&arr)

print(arr) // [1,2,3,4,5,6,7,8,9]
1
Saranjith

私はその目的のためにできるだけ単純な拡張をしました。

extension Array where Element: Equatable {

    func containsHowMany(_ elem: Element) -> Int {
        return reduce(0) { $1 == elem ? $0 + 1 : $0 }
    }

    func duplicatesRemoved() -> Array {
        return self.filter { self.containsHowMany($0) == 1 }
    }

    mutating func removeDuplicates() {
        self = self.duplicatesRemoved(()
    }
}

duplicatesRemoved()を使用して、重複した要素を削除した新しい配列を取得することも、removeDuplicates()を使用して自分自身を変更することもできます。見る:

let arr = [1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 7, 8]

let noDuplicates = arr.duplicatesRemoved()
print(arr) // [1, 1, 1, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 7, 8]
print(noDuplicates) // [1, 2, 3, 4, 5, 6, 7, 8]

arr.removeDuplicates()
print(arr) // [1, 2, 3, 4, 5, 6, 7, 8]
1
Igor Silva

値を削除して配列を変更するためのuniq()uniqInPlace()関数を提供するのは良いことだと思います。これはSwiftが提供するsort()sortInPlace()関数と同じように機能します。また、それは配列なので、元々の要素の順序を守るべきです。

extension Array where Element: Equatable {

    public func uniq() -> [Element] {
        var arrayCopy = self
        arrayCopy.uniqInPlace()
        return arrayCopy
    }

    mutating public func uniqInPlace() {
        var seen = [Element]()
        var index = 0
        for element in self {
            if seen.contains(element) {
                removeAtIndex(index)
            } else {
                seen.append(element)
                index++
            }
        }
    }
}

定数の配列(つまりvar)を変更することはできないので、変数の配列(つまりlet)に対してのみuniqInPlace()を使用できます。

いくつかの使用例

var numbers = [1, 6, 2, 2, 4, 1, 5]
numbers.uniqInPlace() // array is now [1, 6, 2, 4, 5]

let strings = ["Y", "Z", "A", "Y", "B", "Y", "Z"]
let uniqStrings = strings.uniq() // uniqStrings is now ["Y", "Z", "A", "B"]
0
lammert

最も簡単な方法は、一意の要素を格納し、要素の順序を保持する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)
0
sgl0v

一意の値を保持し、配列内のソートを保持します。

(Swift 3を使用)

    var top3score: [Int] = []


    outerLoop: for i in 0..<top10score.count {
        dlog(message: String(top10score[i]))

        if top3score.count == 3 {
            break
        }

        for aTop3score in top3score {
            if aTop3score == top10score[i] {
                continue outerLoop
            }
        }

        top3score.append(top10score[i])

    }

    print("top10score is \(top10score)")  //[14, 5, 5, 5, 3, 3, 2, 2, 2, 2]
    print("top3score is \(top3score)")   //[14, 5, 3]
0
oOEric

機能的なプログラマーのように考えてください。

要素がすでに出現したかどうかに基づいてリストをフィルタリングするには、インデックスが必要です。インデックスを取得するにはenumeratedを、値リストに戻るにはmapを使用できます。

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

これは順序を保証します。順序を気にしないのであれば、既存のArray(Set(myArray))の答えはより単純で、おそらくもっと効率的です。

0
Tim MB

私の解決策は、ハッシュマップアクセスがO(1)であり、フィルターがO(n)であるため、O(n)の時間になりそうです。また、クロージャによって、プロパティを選択して、順番に要素を区別するために使用します。

extension Sequence {

    func distinct<T: Hashable>(by: (Element) -> T) -> [Element] {
        var seen: [T: Bool] = [:]
        return self.filter { seen.updateValue(true, forKey: by($0)) == nil }
    }
}
0
Michał Ziobro

これは、カスタムマッチング関数を使用してシーケンスを一意にするためのより柔軟な方法です。

extension Sequence where Iterator.Element: Hashable {

    func unique(matching: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] {

        var uniqueArray: [Iterator.Element] = []
        forEach { element in
            let isUnique = uniqueArray.reduce(true, { (result, item) -> Bool in
                return result && matching(element, item)
            })
            if isUnique {
                uniqueArray.append(element)
            }
        }
        return uniqueArray
    }
}
0
MarkHim

Swift 4では、結果を配列に変換したくない場合は必要ありませんが、Setを使用して変換できます。結果はデフォルトではソートされませんが、printステートメントに示されているように、配列を返すsorted()でそれを行うことができます。

let array = [1, 4, 2, 2, 6, 24, 15, 2, 60, 15, 6]

var result = Set<Int>()
_ = array.map{ result.insert($0) }

print(result.sorted())  // [1, 2, 4, 6, 15, 24, 60]
0
Johannes

時間の複雑さがo(n)である高次関数を作成しました。また、必要なタイプを返すマップのような機能。

extension Sequence {
    func distinct<T,U>(_ provider: (Element) -> (U, T)) -> [T] where U: Hashable {
        var uniqueKeys = Set<U>()
        var distintValues = [T]()
        for object in self {
            let transformed = provider(object)
            if !uniqueKeys.contains(transformed.0) {
                distintValues.append(transformed.1)
                uniqueKeys.insert(transformed.0)
            }
        }
        return distintValues
    }
}
0
Abhijit