2017-05-07 5 views
0

多くのコードの重複に頼らずに、異なるenumをセットにグループ化して相互メンバーシップをテストする良い方法はありますか?私は.coldBeverageを得るときたとえば列挙型セットの相互メンバーシップをテストする最良の方法

は、以下、私が[.cola, .milk, .wine]を取得し、私は.cola.milk、または.wineのいずれかを取得する場合も同様に、私は.coldBeverageを取得します。

enum BeverageType { 
    case coldBeverage 
    case hotBeverage 
} 

enum Beverage { 
    case cola 
    case milk 
    case wine 
    case coffee 
    case tea 
    case hotChocolate 
} 

もちろん、私は常に各列挙型にvarを作成し、それぞれの型の相互関係を入力できます。他の構造があれば興味がありました。あなたが列挙型のいずれかで静的辞書を使用して重複を避けることができ

extension BeverageType { 
    var associatedBeverages: [Beverage] { 
     switch self { 
      case .coldBeverage: 
       return [.cola, .milk, .wine] 
      case .hotBeverage: 
       return [.coffee, .tea, .hotChocolate] 
     } 
    } 
} 

extension Beverage { 
    var beverageType: BeverageType { 
     switch self: 
      case .cola: 
       return .coldBeverage 
      case .milk: 
       return .coldBeverage 
      //etc... 
    } 

} 
+0

多分関連します。http:/ /stackoverflow.com/questions/36819163/optionsettype-and-enums –

答えて

1

すなわち

extension BeverageType 
{ 
    var associatedBeverages:[Beverage] { return Beverage.associatedBeverages[self]! } 
} 

extension Beverage 
{ 
    var beverageType:BeverageType { return Beverage.beverageTypes[self]! } 

    static var beverageTypes:[Beverage:BeverageType] 
    = [ 
     .cola   : .coldBeverage, 
     .milk   : .coldBeverage, 
     .wine   : .coldBeverage, 
     .coffee  : .hotBeverage, 
     .tea   : .hotBeverage, 
     .hotChocolate : .hotBeverage 
    ] 

    static var associatedBeverages:[BeverageType:[Beverage]] = 
    { 
     var beveragesByType:[BeverageType:[Beverage]] = [:] 
     Beverage.beverageTypes.forEach 
     {beveragesByType[$0.1] = (beveragesByType[$0.1] ?? []) + [$0.0]} 
     return beveragesByType 
    }()  
} 

このアプローチは、他に列挙エントリ(のリストを複製する必要はありません。マッピング、あなたはどこかでやる必要があります)。大規模または頻繁に使用される列挙型で重要になる可能性のある順次検索よりも効率的です。

静的変数は1回だけ評価されるため、2回目以降の使用では、関係の両方向に辞書のO(1)パフォーマンスが役立ちます。

[BeverageType:[Beverage]]から[Beverage:BeverageType]まで辞書を構築することができます。また、静的変数をBeverageType列挙体の各列挙型またはすべてに配置することもできます。

私は飲み物がビバレッジタイプを知っていて、新しい飲み物に拡張される可能性が高いと感じましたので、私はその関係を多方向に定義することを選択しました。

これは、逆辞書のボイラープレートコードが拡張を汚染しないように、これらの状況で使用する双方向ディクショナリ(汎用)クラスを定義することによってさらに一般化することができます。

[EDIT]関係のための双方向の辞書を使用すると、定義はしてもきれいになり:

extension BeverageType 
{ 
    var associatedBeverages:[Beverage] { return Beverage.beverageTypes[self] } 
} 

extension Beverage 
{ 
    var beverageType:BeverageType { return Beverage.beverageTypes[self]! } 

    static var beverageTypes = ManyToOne<Beverage,BeverageType>(
    [ 
     .coldBeverage : [.cola, .milk, .wine], 
     .hotBeverage : [.coffee, .tea, .hotChocolate] 
    ]) 
} 

struct ManyToOne<M:Hashable,O:Hashable> 
{ 
    var manyToOne:[M:O] = [:] 
    var oneToMany:[O:[M]] = [:] 

    init(_ m2o:[M:O]) 
    { 
     manyToOne = m2o 
     for (many,one) in m2o { oneToMany[one] = (oneToMany[one] ?? []) + [many] } 
    } 

    init(_ o2m:[O:[M]]) 
    { 
     oneToMany = o2m 
     for (one,many) in o2m { many.forEach{ manyToOne[$0] = one } } 
    } 

    subscript(many:M) -> O? { return manyToOne[many] } 
    subscript(one:O) -> [M] { return oneToMany[one] ?? [] } 
} 
+0

これは素晴らしいです!ありがとうございました。これを行う方法はおそらく複数ありますが、私はそれを正しいものとしてマークしています。それを一般的にするための+1! +1でパフォーマンスを議論する。 – MH175

0

あなたが他を定義するには1つのメンバーシップを使用することができます。

extension Beverage { 
    static var beverages: [Beverage] { 
     return [.cola, .milk, .wine, .coffee, .tea, .hotChocolate] 
    } 

    var type: BeverageType { 
     switch self { 
     case .cola, .milk, .wine: 
      return .coldBeverage 
     case .coffee, .tea, .hotChocolate: 
      return .hotBeverage 
     } 
    } 
} 

extension BeverageType { 
    var associatedBeverages: [Beverage] { 
     return Beverage.beverages.filter { $0.type == self } 
    } 
} 
関連する問題