测试一组枚举的相互成员资格的最佳方法
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
【讨论】:
以上是关于测试一组枚举的相互成员资格的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章