首页 > 解决方案 > 如何调整字典的值以快速阅读?

问题描述

已编辑的问题:如何快速调整字典的值以供阅读?

我想在不改变原点的情况下调整字典的值以供阅读。我实现了以下类来做到这一点。

class DictionaryView<Key, Value> where Key: Hashable {
   let origin: Dictionary<Key, Value>
   let map: (Value) -> Value
   
   init(_ origin: Dictionary<Key, Value>,
        map: @escaping (Value) -> Value) {
       self.origin = origin
       self.map = map
    }

   subscript(_ key: Key) -> Value?{
      let value = origin[key]
      return value == nil ? value : map(value!)
   }

}

但没有像我预期的那样工作。以下代码

var origin = ["A":2, "B":3]
var adapted = DictionaryView(origin, map: { $0 * 2 })
origin["C"] = 6

print(origin)
print(adapted["A"])
print(adapted["B"])
print(adapted["C"]) 

给我输出:

["B": 3, "C": 6, "A": 2]
可选(4)
可选(6)

我需要进行调整,以打印 Optional(12) insted of nil。怎么做?


原始问题:如何快速调整字典的值?

我有一本字典origin

var origin = ["A":2, "B":3]

并希望创建一个基于origin但包含双值的新字典。我天真的解决方案是通过mapValues

var adapted = origin.mapValues { $0 * 2 }

但是这个解决方案会根据origin' 状态的时刻创建一个新的转换字典。例如下面的代码

origin["C"] = 6

print(origin)
print(adapted)

输出

[“A”:1,“B”:2,“C”:6]
[“A”:2,“B”:4]

但我想要真正的适应。我需要一个解决方案,它将为上面的代码输出如下结果。

[“A”:1,“B”:2,“C”:6]
[“A”:2,“B”:4,“C”:12]

我是 swift 新手,对标准库没有深入的了解。在开始自行车设计之前,我要问:快速解决这个问题的常见方法是什么?


备注 1

我在真实情况下发现了问题,但创建了一个简化示例来提取当前问题的问题本质(避免细节的干扰)。但正如我所看到的,有必要澄清这个问题。

我需要实现 observable 模式并在 Observable.swift 文件中开发了它的 4 个部分。

订阅:

struct Subscription {
    private let handler: () -> ()
    
    init(cancel handler: @escaping () -> ()) {
        self.handler = handler
    }
    
    func cancel() {
        handler()
    }
}

观察员:

struct Observer<Event> {
    private let handler: (Event) -> ()
    
    init(send handler: @escaping (Event) -> ()) {
        self.handler = handler
    }
    
    func send(_ event: Event) {
        handler(event)
    }
}

可观察的:

class Observable<Event> {
    
    fileprivate var observers: [UUID : Observer<Event>] = [:]
    func subscribe(_ observer: Observer<Event>) -> Subscription {
        let id = UUID()
        observers[id] = observer
        return Subscription(cancel: { self.observers[id] = nil })
    }
}

主题:

class Subject<Event> : Observable<Event> {
    private(set) lazy var observer = Observer<Event>(
        send: { event in
            for o in self.observers.values {
                o.send(event)
            }})
}

作为一个常见的例子,我在客户端类外部提供了一个 Subject 作为 Observable 的实例,并在内部用作 Observer 以进行良好的封装。使用示例:

class Acc {
   private let numberAdded: Observer<Int> 
   let numberDidAdd: Observable<Int>
   
   init() {
     let subject = Subject<Int>()
     numberAdded = subject.observer
     numberDidAdd = subject
   }

   func add(_ number: Int) {
       numberAdded.send(number)
   }
}

let acc = Acc()
acc.numberDidAdd.subscribe(Observer<Int>(send: { print($0) }))
acc.add(4)
acc.add(5)

当我需要一个简单的事件时,这个解决方案对我很有用。当我需要实现更复杂的事件订阅接口时,问题就开始了。我需要提供一个事件字典(外部观察者,内部观察者)。以下代码是真实上下文的一部分。描述这种上下文并不容易,但我认为可以从代码中捕捉到它。

class RealClass {

    let buttonEvents = ButtonEvents()

    override func viewDidLoad() {
        super.viewDidLoad()

        for (event, observer) in buttonEvents.observers {
            someInternalSubscriptionFunc(event, observer)
        }
        
        buttonEvents.newEventTypeDidAdd.subscribe(
            Observer(send: { event in
                self.someInternalSubscriptionFunc(
                   event, self.buttonEvents.observers[event]!)
            })
    }

    public class ButtonEvents {
        
        private let newEventTypeAdding = Subject<UIControl.Event>()
        private(set) lazy var newEventTypeDidAdd
            : Observable<UIControl.Event> 
            = newEventsTypeAdding
        
        private var subjects: [UIControl.Event : Subject<Point>] = [:]
        fileprivate private(set) lazy var observers
            : [UIControl.Event : Observer<Point>] 
            = subjects.mapValues({ subject in subject.observer })
        
        public subscript(event: UIControl.Event) -> Observable<Point> {
            if subjects[event] == nil {
               subjects[event] = Subject<Point>()
               newEventTypeAdding.send(event)
            }
            
            return subjects[event]!
        }
    }
}

正如我们所见ButtonEvents.observers,这是问题的根源。

我可以重新实现observers为计算属性,但在访问字典项时我会失去 O(1) 的性能。

标签: swift

解决方案


发生这种情况是因为

字典是值类型

你应该在这里做的是使用Computed Property

var adapted: [String: Int] {
    return origin.mapValues { $0 * 2 }
}

现在在任何地方调用它,结果将符合预期


推荐阅读