【问题标题】:Initializing a Dictionary(uniqueKeysWithValues:) from KeyValuePairs从 KeyValuePairs 初始化 Dictionary(uniqueKeysWithValues:)
【发布时间】:2020-08-29 09:11:36
【问题描述】:
struct Data {
    let storage: [String: Int]
    
    init(_ pairs: KeyValuePairs<String, Int>) {
        storage = Dictionary(uniqueKeysWithValues: pairs)
    }
}

编译错误:

Initializer 'init(uniqueKeysWithValues:)' 需要类型 'KeyValuePairs.Element' (又名 '(key: String, value: Int)') 和 '(String, Int)' 等价

还有什么比使用 KeyValuePairs 初始化 Dictionary(uniqueKeysWithValues:) 更自然的方法!简直可笑,不能直截了当!
requires '(key: String, value: Int)' and '(String, Int)' be equivalent他们是等价的!​​p>

【问题讨论】:

  • storage = Dictionary(uniqueKeysWithValues: Array(pairs)) 应该可以解决问题。 KeyValuePair 不是序列,毕竟是public init&lt;S&gt;(uniqueKeysWithValues keysAndValues: S) where S : Sequence, S.Element == (Key, Value)
  • @Larme 是的,这行得通。我将深入研究文档以理解您的解释,但您的代码可以按预期编译和工作。你能发个帖子吗,我可以把它作为答案:)
  • @Larme 类型不是KeyValuePair,是KeysValue*PAIRS*

标签: swift dictionary swift5


【解决方案1】:

这是因为KeyValuePairs.Element 有标签。

type(of: (key: "", value: 0)) == type(of: ("", 0)) // false

您需要另一个重载或只是就地删除标签。

public extension Dictionary {
  /// Creates a new dictionary from the key-value pairs in the given sequence.
  ///
  /// - Parameter keysAndValues: A sequence of key-value pairs to use for
  ///   the new dictionary. Every key in `keysAndValues` must be unique.
  /// - Returns: A new dictionary initialized with the elements of
  ///   `keysAndValues`.
  /// - Precondition: The sequence must not have duplicate keys.
  @inlinable init<Elements: Sequence>(uniqueKeysWithValues keysAndValues: Elements)
  where Elements.Element == Element {
    self.init(
      uniqueKeysWithValues: keysAndValues.map { ($0, $1) }
    )
  }
}
XCTAssertEqual(
  Dictionary(
    uniqueKeysWithValues: ["?": "?", "?‍♀️": "?‍♂️"] as KeyValuePairs
  ),
  .init(
    uniqueKeysWithValues: [("?", "?"), ("?‍♀️", "?‍♂️")]
  )
)

【讨论】:

  • 这不处理重复值。它将在Data(["a": 1, "b": 2, "a": 3] as KeyValuePairs) 上失败,并出现致命错误:键值重复:'a'
  • 是的,见前提。 Swift 4 中还引入了另一个处理这个问题的重载。
【解决方案2】:

由于 Swift 不支持 Splatting(目前),您可以通过以下方式实现它:

struct Data {
    let storage: [String: Int]

    init(_ pairs: KeyValuePairs<String, Int>) {
        storage = Dictionary(uniqueKeysWithValues: pairs.reduce(into: [String: Int]()) { $0[$1.0] = $1.1 } .map { $0 })
    }
}

用法:

let data = Data(KeyValuePairs(dictionaryLiteral: ("a", 1), ("b", 2)))

【讨论】:

    【解决方案3】:

    你也可以使用reduce:

    storage = pairs.reduce(into: [String: Int]()) { $0[$1.key] = $1.value }
    

    即使您在 pairs 中有重复的键,这也可以工作(目前它从重复项中获取最后一项:

    let data = Data(["a": 1, "b": 2, "a": 3] as KeyValuePairs)
    print(data.storage) 
    // ["a": 3, "b": 2]
    

    如果你需要它来拿你可以做的第一个项目:

    storage = pairs.reduce(into: [String: Int]()) { $0[$1.key] = $0[$1.key] ?? $1.value }
    

    (或更短)

    storage = pairs.reduce(into: [String: Int]()) { $0[$1.0] = $0[$1.0] ?? $1.1 }
    

    打印出来:

    let data = Data(["a": 1, "b": 2, "a": 3] as KeyValuePairs)
    print(data.storage) 
    // ["a": 1, "b": 2]
    
    【解决方案4】:

    • 修复:

    storage = Dictionary(uniqueKeysWithValues: Array(pairs))
    

    • 为什么:
    您尝试使用的方法是:

    public init<S>(uniqueKeysWithValues keysAndValues: S) where S : Sequence, S.Element == (Key, Value)
    

    而且它缺少S.Element == (Key, Value) 合规性。

    • 更进一步:
    请注意,如果您有重复的密钥,则会出现错误。然后你可以使用:

    storage = Dictionary(Array(paris)) { _, new in
        return new //if you want to keep the last "key" value, or the reverse
    }
    

    • 其他可能性:
    convert [(key: String, value: String)] in [String:String]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-09
      • 1970-01-01
      • 1970-01-01
      • 2020-07-26
      • 1970-01-01
      • 2011-08-09
      • 1970-01-01
      相关资源
      最近更新 更多