web-dev-qa-db-ja.com

Swiftで一意のオブジェクトリストの配列を作成する方法

Objective-CのNSSetNSMutableSetのようなSwift言語)で一意のオブジェクトリストを作成するにはどうすればよいですか。

54
Subramanian P

Swift 1.2(Xcode 6.3 beta)以降、Swiftにはネイティブセットタイプがあります。リリースノートから:

新しいSetデータ構造が含まれ、完全な値のセマンティクスを備えた一意の要素の一般的なコレクションを提供します。 NSSetとブリッジし、ArrayおよびDictionaryに類似した機能を提供します。

簡単な使用例を次に示します。

// Create set from array literal:
var set = Set([1, 2, 3, 2, 1])

// Add single elements:
set.insert(4)
set.insert(3)

// Add multiple elements:
set.unionInPlace([ 4, 5, 6 ])
// Swift 3: set.formUnion([ 4, 5, 6 ])

// Remove single element:
set.remove(2)

// Remove multiple elements:
set.subtractInPlace([ 6, 7 ])
// Swift 3: set.subtract([ 6, 7 ])

print(set) // [5, 3, 1, 4]

// Test membership:
if set.contains(5) {
    print("yes")
}

しかし、はるかに多くの方法が利用可能です。

Update:セットは、Swiftドキュメントの "Collection Types" の章にも記載されています。 。

51
Martin R

Swiftでは任意のObjective-Cクラスを使用できます。

var set = NSMutableSet()
set.addObject(foo)
14
Austin

Swiftにはセットの概念はありません。 SwiftでNSMutableSetを使用すると、ダミー値を保持するDictionaryを使用するよりも遅くなる可能性があります。

var mySet: Dictionary<String, Boolean> = [:]
mySet["something"]= 1

次に、キーを繰り返し処理します。

10

組み込みのSetおよびArrayに似たDictionary型を作成しました。ブログの投稿1と2、およびGitHubリポジトリを次に示します。

9
Nate Cook
extension Array where Element: Hashable {
    var setValue: Set<Element> {
        return Set<Element>(self)
    }
}

let numbers = [1,2,3,4,5,6,7,8,9,0,0,9,8,7]
let uniqueNumbers = numbers.setValue    // {0, 2, 4, 9, 5, 6, 7, 3, 1, 8}

let names = ["John","Mary","Steve","Mary"]
let uniqueNames = names.setValue    // {"John", "Mary", "Steve"}
7
Leo Dabus

内部辞書を持つ構造体が行く方法だと思いました。使用し始めたばかりなので、完全ではなく、パフォーマンスについてはまだわかりません。

struct Set<T : Hashable>
{
    var _items : Dictionary<T, Bool> = [:]

    mutating func add(newItem : T) {
        _items[newItem] = true
    }

    mutating func remove(newItem : T) {
        _items[newItem] = nil
    }

    func contains(item: T) -> Bool {
        if _items.indexForKey(item) != nil { return true } else { return false }
    }

    var items : [T] { get { return [T](_items.keys) } }
    var count : Int { get { return _items.count } }
}
4
Gary Makin

Setオブジェクトは実際に非常に簡単に作成できます(GoZonerとは矛盾して、組み込みのcontainsメソッドがあります)。

class Set<T : Equatable> {
    var items : T[] = []

    func add(item : T) {
        if !contains(items, {$0 == item}) {
            items += item
        }
    }
}

また、カスタム演算子を宣言することもできます。

@assignment @infix func += <T : Equatable> (inout set : Set<T>, items : T[]) -> Set<T> {
    for item in items {
        set.add(item)
    }
    return set
}
3
Kametrixom

このような場合、常に重要な要素は、オブジェクトの比較方法と、セットに入れるオブジェクトのタイプです。 Swiftディクショナリ、Setオブジェクトがディクショナリキーである場合)は、キータイプ(String、Int、Double、Bool、valueless Enumerationsまたはhashable)の制限に基づいて問題になる可能性があります。

ハッシュ関数を定義できる場合オブジェクトタイプで、辞書を使用できます。 オブジェクトが順序付け可能な場合の場合、ツリーを定義できます。 オブジェクトが==とのみ比較可能の場合、既存のオブジェクトを検出するには、セット要素を反復処理する必要があります。

// When T is only Equatable
class Set<T: Equatable> {
  var items = Array<T>()

  func hasItem (that: T) {
   // No builtin Array method of hasItem... 
   //   because comparison is undefined in builtin Array   
   for this: T in items {
     if (this == that) {
       return true
     }
   }
   return false
  }

  func insert (that: T) {
    if (!hasItem (that))
      items.append (that)
  }
}

上記はSwift Set;を構築する例です。この例では、Equatableのみのオブジェクトを使用しました。効率的なSet実装につながります(O(N)検索の複雑さ-上記は一例です)。

2
GoZoner

したがって、配列でSetを作成するのはひどい考えだと思います-O(n)はそのセットの時間の複雑さです。

辞書を使用する素敵なセットをまとめました: https://github.com/evilpenguin/Swift-Stuff/blob/master/Set.Swift

1
EvilPenguin

この問題を解決する関数を作成しました。

public func removeDuplicates<C: ExtensibleCollectionType where C.Generator.Element : Equatable>(aCollection: C) -> C {
    var container = C()

    for element in aCollection {
        if !contains(container, element) {
            container.append(element)
        }
    }

    return container
}

使用するには、この関数に重複した要素を含む配列を渡すだけです。そして、一意性が保証された配列を返します。

必要に応じて、DictionaryString、またはExtensibleCollectionTypeプロトコルに準拠するものを渡すこともできます。

1
WeZZard

NSObjectから派生したクラスの特別な場合

nSObjectのデフォルトのEquitable(&Hashable)準拠は基本的にゴミであるため、適切なものを提供することをお勧めします

static func == (lhs: YourClassDerivedFromNSObject, rhs: YourClassDerivedFromNSObject) -> Bool {

setに挿入された重複を摘み取りたくない実装

0
Anton Tropashko