测试一组枚举的相互成员资格的最佳方法

Posted

技术标签:

【中文标题】测试一组枚举的相互成员资格的最佳方法【英文标题】:Best way to test mutual membership for set of enums 【发布时间】:2017-05-07 04:02:29 【问题描述】:

有没有一种好方法可以将不同的枚举分组到集合中以测试相互成员资格,而无需大量重复代码?

例如,在下面,当我得到.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...
    


【问题讨论】:

可能相关:***.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
   ()       

这种方法不需要复制枚举条目列表(除了映射,您必须在某处进行)。它也比顺序搜索更有效,顺序搜索可能对大型或经常使用的枚举很重要。

静态变量只计算一次,因此从第二次使用开始,您将受益于字典在关系的两个方向上的 O(1) 性能。

请注意,您可以反过来构建字典(即从 [BeverageType:[Beverage]] 到 [Beverage:BeverageType]),您还可以将静态变量放在每个枚举中或全部放在 BeverageType 枚举中。

我觉得饮料应该知道它们的 BeverageType 并且更有可能扩展到新的饮料,所以我选择在那个(多对一)方向定义关系。

这甚至可以通过定义在这些情况下使用的双向字典(通用)类来进一步概括,以便倒排字典的样板代码不会污染扩展。

[编辑] 使用关系的双向字典,定义变得更加清晰:

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] ?? [] 

【讨论】:

这太棒了!谢谢你。尽管可能有多种方法可以做到这一点,但我将其标记为正确。 +1 使其通用!!! +1 讨论性能。【参考方案2】:

您可以使用一个成员来定义另一个成员:

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 
    

【讨论】:

以上是关于测试一组枚举的相互成员资格的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

迭代器的成员资格测试

测试 Scala 类型类中的成员资格

结合多个成员资格测试[重复]

熊猫数据框列中的成员资格测试

有没有一种简单的方法来测试您是不是匹配一组枚举中的一个?

是否有任何方便的方法可以在 Xcode 中枚举和调用 XCTestCase 类的测试?