字典的每个值组合

时间:2020-09-28 00:54:51

标签: arrays swift dictionary

曾经绞尽脑汁,似乎无法提出一个优雅的解决方案。想知道是否有人可以帮助我。

我有一台Swift字典,每个键都有一个值数组,就像这样...

[A:[1, 2, 3], B:[4, 5, 6], C:[7, 8, 9]]

我需要将其转换成带有值的每种组合的字典数组...

[
[A:1, B:4, C:7],
[A:1, B:4, C:8],
[A:1, B:4, C:9],
[A:1, B:5, C:7],
[A:1, B:5, C:8],
[A:1, B:5, C:9],
[A:1, B:6, C:7],
[A:1, B:6, C:8],
[A:1, B:6, C:9],
[A:2, B:4, C:7],
[A:2, B:4, C:8],
[A:2, B:4, C:9],
[A:2, B:5, C:7],
[A:2, B:5, C:8],
[A:2, B:5, C:9],
[A:2, B:6, C:7],
...
[A:3, B:6, C:9],
]

2 个答案:

答案 0 :(得分:0)

这是一种递归解决方案,它适用于原始字典中任意数量的键/数组对以及values数组中任意数量的值:

let dict = ["A":[1, 2, 3], "B":[4, 5, 6], "C":[7, 8, 9]]

func combine(source: [String : [Int]], partials: [[String : Int]] = [], final: inout [[String : Int]]) {

    if source.isEmpty {
        // base step of recursion
        // there are no more (k:v) pairs in source, so add all of the partials (now final)
        // to the final array
        final.append(contentsOf: partials)
    } else {
        // source has a (k:v) pair, so take the first one
        let (k, vals) = source.first!
        var newsource = source
        
        // remove key from newsource
        newsource[k] = nil
        
        // for each value in the key
        for val in vals {
            // add (k:v) to each partial dictionary
            var newpartials = partials
            
            // If new partials array is empty
            if newpartials.isEmpty {
                // create the array with the first [k:v]
                newpartials = [[k : val]]
            } else {
                // otherwise, add [k:v] to each of the partial dictionaries
                for pidx in newpartials.indices {
                    newpartials[pidx][k] = val
                }
            }
            // recursive call to process the next value in source
            combine(source: newsource, partials: newpartials, final: &final)
        }
        
    }
}

var result = [[String : Int]]()
combine(source: dict, final: &result)
print(result)
print(result.count)

[[“ A”:1,“ B”:4,“ C”:7],[“ A”:2,“ B”:4,“ C”:7],[“ A”:3 ,“ B”:4,“ C”:7],[“ C”:7,“ B”:5,“ A”:1],[“ C”:7,“ B”:5,“ A” :2],[“ C”:7,“ B”:5,“ A”:3],[“ C”:7,“ B”:6,“ A”:1],[“ C”:7 ,“ B”:6,“ A”:2],[“ C”:7,“ B”:6,“ A”:3],[“ C”:8,“ B”:4,“ A” :1],[“ C”:8,“ B”:4,“ A”:2],[“ C”:8,“ B”:4,“ A”:3],[“ C”:8 ,“ B”:5,“ A”:1],[“ C”:8,“ B”:5,“ A”:2],[“ C”:8,“ B”:5,“ A” :3],[“ B”:6,“ C”:8,“ A”:1],[“ B”:6,“ C”:8,“ A”:2],[“ B”:6 ,“ C”:8,“ A”:3],[“ A”:1,“ C”:9,“ B”:4],[“ A”:2,“ C”:9,“ B” :4],[“ A”:3,“ C”:9,“ B”:4],[“ B”:5,“ A”:1,“ C”:9],[“ B”:5 ,“ A”:2,“ C”:9],[“ B”:5,“ A”:3,“ C”:9],[“ B”:6,“ A”:1,“ C” :9],[“ B”:6,“ A”:2,“ C”:9],[“ B”:6,“ A”:3,“ C”:9]]

27


通用解决方案

没有理由将其限制为StringInt。密钥应为符合Hashable的任何类型。

要使函数通用,请将签名更改为:

func combine<KEY, VALUE>(source: [KEY : [VALUE]], partials: [[KEY : VALUE]] = [],
    final: inout [[KEY : VALUE]]) where KEY: Hashable {

制作Dictionary extension

@LeoDabus将此答案扩展为extension上的Dictionary,其中ValueCollection(谢谢Leo!):

extension Dictionary where Value: Collection {
    func permutations() -> [[Key: Value.Element]] {
        guard !isEmpty else { return [] }
        var permutations: [[Key: Value.Element]] = []
        permutate(&permutations)
        return permutations
    }
    private func permutate(_ permutations: inout [[Key: Value.Element]], _ dictionaries: [[Key: Value.Element]] = []) {
        if let (key, value) = first {
            var dictionary = self
            dictionary[key] = nil
            for element in value {
                var dictionaries = dictionaries
                if dictionaries.isEmpty {
                    dictionaries += CollectionOfOne([key: element])
                } else {
                    for index in dictionaries.indices {
                        dictionaries[index][key] = element
                    }
                }
                dictionary.permutate(&permutations, dictionaries)
            }
        } else {
            permutations += dictionaries
        }
    }
}

let dict = ["A":[1, 2, 3], "B":[4, 5, 6], "C":[7, 8, 9]]
let result = dict.permutations()
print(result)
print(result.count)

[[“ B”:4,“ A”:1,“ C”:7],[“ B”:4,“ A”:2,“ C”:7],[“ B”:4 ,“ A”:3,“ C”:7],[“ A”:1,“ B”:4,“ C”:8],[“ A”:2,“ B”:4,“ C” :8],[“ A”:3,“ B”:4,“ C”:8],[“ A”:1,“ B”:4,“ C”:9],[“ A”:2 ,“ B”:4,“ C”:9],[“ A”:3,“ B”:4,“ C”:9],[“ C”:7,“ A”:1,“ B” :5],[“ C”:7,“ A”:2,“ B”:5],[“ C”:7,“ A”:3,“ B”:5],[“ C”:8 ,“ A”:1,“ B”:5],[“ C”:8,“ A”:2,“ B”:5],[“ C”:8,“ A”:3,“ B” :5],[“ C”:9,“ A”:1,“ B”:5],[“ C”:9,“ A”:2,“ B”:5],[“ C”:9 ,“ A”:3,“ B”:5],[“ B”:6,“ C”:7,“ A”:1],[“ B”:6,“ C”:7,“ A” :2],[“ B”:6,“ C”:7,“ A”:3],[“ B”:6,“ A”:1,“ C”:8],[“ B”:6 ,“ A”:2,“ C”:8],[“ B”:6,“ A”:3,“ C”:8],[“ B”:6,“ A”:1,“ C” :9],[“ B”:6,“ A”:2,“ C”:9],[“ B”:6,“ A”:3,“ C”:9]]

27

答案 1 :(得分:0)

您确定最后需要一系列词典吗?如果没有,那么这是一个交错的键/值对数组:

let keyValuePairArrays =
  ["A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]]
  .sorted(\.key)
  .map { key, value in
    value.map { (key, $0) }
  }
  .combinations

如果您真的需要字典,只需将其映射即可! ?

keyValuePairArrays.map(Dictionary.init)

支持代码:

public extension Sequence where Element: Sequence {
  var combinations: [[Element.Element]] {
    guard let initialResult = ( first?.map { [$0] } )
    else { return [] }

    return dropFirst().reduce(initialResult) { combinations, iteration in
      combinations.flatMap { combination in
        iteration.map { combination + [$0] }
      }
    }
  }
}
public extension Sequence {
  /// The first element of the sequence.
  /// - Note: `nil` if the sequence is empty.
  var first: Element? {
    var iterator = makeIterator()
    return iterator.next()
  }

  /// Sorted by a common `Comparable` value.
  func sorted<Comparable: Swift.Comparable>(
    _ comparable: (Element) throws -> Comparable
  ) rethrows -> [Element] {
    try sorted(comparable, <)
  }

  /// Sorted by a common `Comparable` value, and sorting closure.
  func sorted<Comparable: Swift.Comparable>(
    _ comparable: (Element) throws -> Comparable,
    _ areInIncreasingOrder: (Comparable, Comparable) throws -> Bool
  ) rethrows -> [Element] {
    try sorted {
      try areInIncreasingOrder(comparable($0), comparable($1))
    }
  }
}