-2

I have a dictionary with two Int’s A:B, and I want create a new dictionary that includes B as an index (with no repetition) and A as a value (only for repeated B’s):

var myDict : [Int:Int] = [12:2345, 14:2345, 99:1111, 67:1111, 77:7657, 132:3345, 199:6778]

Desired output:

var newDict: [Int:[Int]] = [2345: [ 12 , 14 ] , 1111: [ 99 , 67] ]

Note: the original dictionary contains over a thousand entries.

3 Answers3

1

You loop through the first dict by enumerating it, that way you can switch the values in to the new dict

var newDict: [Int:[Int]] = [:]
let myDict : [Int:Int] = [12:2345, 14:2345, 99:1111, 67:1111, 77:7657, 132:3345, 199:6778]



     for values in myDict.enumerated() {
            var newValue = newDict[values.element.value] ?? []
            newValue.append(values.element.key)
            newDict[values.element.value] = newValue
        }

     newDict = newDict.filter { (key, value) -> Bool in
             value.count > 1
        }
Vollan
  • 1,887
  • 11
  • 26
1

Here is the power of swift:

let newDict = Dictionary(grouping: myDict, by: {$0.value}).filter({$0.value.count > 1}).mapValues({$0.map({$0.key})})
print(newDict)

Output: [1111: [67, 99], 2345: [12, 14]]

TheTiger
  • 13,264
  • 3
  • 57
  • 82
  • It's smooth with everything on 1 line, however, it decreases the readability :/ – Vollan Apr 13 '18 at 06:41
  • No! Its clear for who knows the uses of `grouping`, `map` and `filters`. If you read it carefully its clear how is it working. – TheTiger Apr 13 '18 at 06:42
  • I agree that it's clear using those methods, but using all in 1 line is not clear. – Vollan Apr 13 '18 at 06:48
  • For that you can use two more variables containing the result of each filter. I just wanted to avoid the loop as OP mentioned `Note: the original dictionary contains over a thousand entries.` Obviously this will be faster than two loops. – TheTiger Apr 13 '18 at 06:50
0

Please use this code:

var myDict: [Int:Int] = [12:2345, 14:2345, 99:1111, 67:1111, 77:7657, 132:3345, 199:6778]
let values = myDict.values
let tempValueSet = Set<Int>(values)
let uniqueValues = Array(tempValueSet)
var result = [Int: [Int]]()

for item in uniqueValues {
    result[item] = myDict.allKeys(forValue: item)
}
print(result)

And this is Dictionary extension:

extension Dictionary where Value: Equatable {
    func allKeys(forValue val: Value) -> [Key] {
        return self.filter { $1 == val }.map { $0.0 }
    }
}

Desired output:

[6778: [199], 1111: [99, 67], 7657: [77], 3345: [132], 2345: [12, 14]]

For more reference about this extension : https://stackoverflow.com/a/27218964/2284065

If you don't want to use extension then you can use this code too :

var myDict: [Int:Int] = [12:2345, 14:2345, 99:1111, 67:1111, 77:7657, 132:3345, 199:6778]
let values = myDict.values
let tempValueSet = Set<Int>(values)
let uniqueValues = Array(tempValueSet)
var result = [Int: [Int]]()

for item in uniqueValues {
    result[item] = (myDict as NSDictionary).allKeys(for: item) as! [Int]
}
print(result)
Jayesh Thanki
  • 2,037
  • 2
  • 23
  • 32