我想调整字典的值以供阅读而不更改原点。我实现了以下课程。
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)
无
我需要进行改编,以打印出由nil插入的Optional(12)。 怎么做?
我有一本字典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]
我是新手,对标准库不了解。 在开始自行车设计之前,我想问:快速解决这个问题的通用解决方案是什么?
备注1
我在实际情况中发现了问题,但是创建了一个简化的示例来提取当前问题的本质(避免细节混乱)。但据我所知,有必要解决这个现实情况。
我需要实现可观察模式,并在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)
}})
}
通常,我在客户端类外部提供了一个Observable的Subject实例,并在内部将其用作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)。
答案 0 :(得分:3)
这是因为
字典是值类型
您应该在这里使用Computed Property
var adapted: [String: Int] {
return origin.mapValues { $0 * 2 }
}
现在将其命名为结果符合预期的任何地方
答案 1 :(得分:2)
根据您的最后修改:
struct AdaptedDict<Key: Hashable, Value> {
private var origin: UnsafeMutablePointer<[Key: Value]>
private let transform: (Value) -> Value
init(_ origin: inout [Key: Value], transform: @escaping (Value) -> Value) {
self.origin = UnsafeMutablePointer(&origin)
self.transform = transform
}
subscript(_ key: Key) -> Value? {
if let value = origin.pointee[key] {
return transform(value)
}
return nil
}
}
var origin = ["A": 10, "B": 20]
var adaptedDict = AdaptedDict(&origin) { $0 * 2 }
print(origin["A"], adaptedDict["A"])
origin["A"] = 20
print(origin["A"], adaptedDict["A"])
因此,基本上,您使用指针存储字典。
答案 2 :(得分:1)
Swift.Dictionary
具有值语义。如果需要引用语义,则Foundation具有NSMutableDictionary
。除非您有真正的性能问题,否则您真的不应该担心Swift.Dictionary
(即,您正在变异数百万条记录,并且确定它实际上在写入时触发了复制)。
import PlaygroundSupport
import Foundation
let d: NSMutableDictionary = [ "a": 1, "b": 2]
for (key, value) in d {
guard let value = value as? Int else { continue}
d[key] = value * 2
}
print(d)
答案 3 :(得分:0)
正如 Martin R 所说,如果在生成origin
数组后修改adapted
数组不会影响它。因此,您首先创建origin
var origin = ["A":2, "B":3]
然后通过添加origin["C"] = 6
对其进行修改,然后可以创建adapted
数组。
var adapted = origin.mapValues { $0 * 2 }
print(origin)
print(adapted)
这应该给您期望的结果。