How can I expand a Dict(string, array) in Swift 5 - swift

Can I expand the dictionary to an array of pairs in Swift 5 using map/reduce or will I have to do a for each ?
let dict = ["A": ["1","2","3","4"],
"B": ["5","6","7","8"]]
???
//result = [["A", "1"],["A", "2"],....["B", "5"],....]

let result = dict.map { (letter: String, digits: [String]) in
return digits.map { digit in
return [letter, digit]
}
}.reduce([]) {
$0 + $1
}

This one is shortest solution.
let result = dict.map { dic in
dic.value.map { [dic.key : $0] }
}.reduce([], +)

Here's a solution that doesn't need reduce:
let dict = ["A": ["1","2","3","4"],
"B": ["5","6","7","8"]]
let result = dict.map { kv in kv.value.map { [kv.key, $0] } }.flatMap { $0 }

Related

swift: working with string

We have a simple string:
let str = "\"abc\", \"def\",\"ghi\" , 123.4, 567, \"qwe,rty\""
If we do this:
let parsedCSV = str
.components(separatedBy: .newlines)
.filter { !$0.isEmpty }
.map { $0.components(separatedBy: ",") }
.map { $0.map { $0.trimmingCharacters(in: .whitespaces) } }
print(parsedCSV)
we get this:
[["\"abc\"", "\"def\"", "\"ghi\"", "123.4", "567", "\"qwe", "rty\""]]
Is there a simple solution (using functional programming) not to split the last element \"qwe,rty\", because we know that it's one whole thing?
Well this is a hack, it works for this case.... not very simple solution for complex issue ...
let str = "\"abc\", \"def\",\"ghi\" , 123.4, 567, \"qwe,rty\""
let parsedCSV = str
.components(separatedBy: .newlines)
.filter { !$0.isEmpty }
.map { $0.components(separatedBy: ",") }
.map { $0.map { $0.trimmingCharacters(in: .whitespaces) } }.reduce([]) { (result, items) -> [String] in
var goodItems = items.filter{ $0.components(separatedBy: "\"").count == 3 || $0.components(separatedBy: "\"").count == 1}
let arr = items.filter{ $0.components(separatedBy: "\"").count == 2}
var join:[String] = []
for x in 0..<arr.count {
let j = x + 1
if j < arr.count {
join = [arr[x] + "," + arr[j]]
}
}
goodItems.append(contentsOf: join)
return goodItems
}
print(parsedCSV)
print out
["\"abc\"", "\"def\"", "\"ghi\"", "123.4", "567", "\"qwe,rty\""]
I've done that.
let str = "_, * ,, \"abc\", 000, def, ghi , 123.4,, 567, \"qwe,rty,eur\", jkl"
let separator = ","
let parsedCSV = str
.components(separatedBy: .newlines)
.filter { !$0.isEmpty }
.map { $0.components(separatedBy: separator).map { $0.trimmingCharacters(in: .whitespaces) } }
.reduce([]) { (result, items) -> [String] in
var result: [String] = []
for item in items {
guard let last = result.last, last.components(separatedBy: "\"").count % 2 == 0 else {
result.append(item)
continue
}
result.removeLast()
let lastModified = record + separator + item
result.append(lastModified)
}
return result
}.map { $0.trimmingCharacters(in: CharacterSet(charactersIn: "\"")) }
print(parsedCSV)
["_", "*", "", "abc", "000", "def", "ghi", "123.4", "", "567",
"qwe,rty,eur", "jkl"]
If you do not mind using Regular Expression, you can write something like this:
let str = "_, * ,, \"abc\", 000, def, ghi , 123.4,, 567, \"qwe,rty,eur\", jkl"
let pattern = "((?:[^\",]|\"[^\"]*\")*)(?:,|$)"
let regex = try! NSRegularExpression(pattern: pattern)
let parsedCSV = regex.matches(in: str, options: .anchored, range: NSRange(0..<str.utf16.count))
.map {$0.range(at: 1)}
.filter {$0.location != NSNotFound && $0.location < str.utf16.count}
.map {String(str[Range<String.Index>($0, in: str)!]).trimmingCharacters(in: .whitespaces)}
.map {$0.trimmingCharacters(in: CharacterSet(charactersIn: "\""))}
print(parsedCSV) //->["_", "*", "", "abc", "000", "def", "ghi", "123.4", "", "567", "qwe,rty,eur", "jkl"]

Swift: Filter a Dictionary with Array as Value

I'm new to Swift programming. For my particular project, I'm trying to filter a dictionary with some user input, and the dictionary's value consists of an array.
Here is some sample code, and what I'm trying to accomplish:
var dictionary = ["a": ["aberration", "abc"], "b" : ["babel", "bereft"]]
var filteredDictionary = [String: [String]]()
var searchText = "aberration"
//getting the first letter of string
var firstLetter = searchText[searchText.startIndex]
With this particular searchText, I'm trying to get:
filteredDictionary = ["a": ["aberration"]]
Edit: I want the dictionary to return with the first letter as its key, and the values with what searchText matches up with. Sorry if it I wasn't clear.
Here is some code I have tried, but obviously, I can't get it to work:
filteredDictionary = dictionary.filter{$0.key == firstLetter && for element in $0.value { element.hasPrefix(searchText) }}
Any help would be appreciated. Thanks.
Here's a solution that maps the values based on the search and then filters out the empty results.
var dictionary = ["a": ["aberration", "abc"], "b" : ["babel", "bereft"]]
var searchText = "aberration"
let filteredDictionary = dictionary.mapValues { $0.filter { $0.hasPrefix(searchText) } }.filter { !$0.value.isEmpty }
print(filteredDictionary)
Output:
["a": ["aberration"]]
Try this:
var dictionary = ["a": ["aberration", "abc"], "b" : ["babel", "bereft"]]
var searchText = "aberration"
var filteredDictionary = dictionary.filter { (key, value) -> Bool in
return (value as! [String]).contains(searchText)
}.mapValues { (values) -> [String] in
return [searchText]
}
print(filteredDictionary)
You can use a combination of filter and map to achieve the desired result.
Output:
["a": ["aberration"]]
let firstLetter = String(searchText[searchText.startIndex])
let filteredDictionary = dictionary
.reduce(into: [String: [String]]()) { (result, object) in
if object.key == firstLetter {
let array = object.value.filter({ $0.hasPrefix(searchText) })
if array.count > 0 {
result[object.key] = array
}
}
}
Output:
["a": ["aberration"]]

Check for duplicate characters in string using for-loops in swift

I did this using while loops but I'm wondering if there's a way to do this with for loops. I'm trying to write this clean so I can write it on a whiteboard for people to understand.
var str = "Have a nice day"
func unique(_ str: String) -> String {
var firstIndex = str.startIndex
while (firstIndex != str.endIndex) {
var secondIndex = str.index(after: firstIndex)
while (secondIndex != str.endIndex) {
if (str[firstIndex] == str[secondIndex]) {
return "Not all characters are unique"
}
secondIndex = str.index(after: secondIndex)
}
firstIndex = str.index(after: firstIndex)
}
return "All the characters are unique"
}
print("\(unique(str))")
You can use the indices of the characters:
var str = "Have a nice day"
func unique(_ str: String) -> String {
for firstIndex in str.characters.indices {
for secondIndex in str.characters.indices.suffix(from: str.index(after: firstIndex)) {
if (str[firstIndex] == str[secondIndex]) {
return "Not all characters are unique"
}
}
}
return "All the characters are unique"
}
print("\(unique(str))")
I used a hash to do it. Not sure how fast it is but it doesn't need to be in my case. (In my case I'm doing phone numbers so I get rid of the dashes first)
let theLetters = t.components(separatedBy: "-")
let justChars = theLetters.joined()
var charsHash = [Character:Int]()
justChars.forEach { charsHash[$0] = 1 }
if charsHash.count < 2 { return false }
... or more compact, as an extension...
extension String {
var isMonotonous: Bool {
var hash = [Character:Int]()
self.forEach { hash[$0] = 1 }
return hash.count < 2
}
}
let a = "asdfasf".isMonotonous // false
let b = "aaaaaaa".isMonotonous // true
Here is the for-loop version of your question.
let string = "Have a nice day"
func unique(_ string: String) -> String {
for i in 0..<string.characters.count {
for j in (i+1)..<string.characters.count {
let firstIndex = string.index(string.startIndex, offsetBy: i)
let secondIndex = string.index(string.startIndex, offsetBy: j)
if (string[firstIndex] == string[secondIndex]) {
return "Not all characters are unique"
}
}
}
return "All the characters are unique"
}
There are a lot of ways this can be achieved and this is just one way of doing it.
As #adev said, there are many ways to finish this. For example, you can use only one for-loop with a dictionary to check the string is unique or not:
Time complexity: O(n). Required O(n) additional storage space for the dictionary.
func unique(_ input: String) -> Bool {
var dict: [Character: Int] = [:]
for (index, char) in input.enumerated() {
if dict[char] != nil { return false }
dict[char] = index
}
return true
}
unique("Have a nice day") // Return false
unique("Have A_nicE-dⒶy") // Return true
let str = "Hello I m sowftware developer"
var dict : [Character : Int] = [:]
let newstr = str.replacingOccurrences(of: " ", with: "")
print(newstr.utf16.count)
for i in newstr {
if dict[i] == nil {
dict[i] = 1
}else{
dict[i]! += 1
}
}
print(dict) // ["e": 5, "v": 1, "d": 1, "H": 1, "f": 1, "w": 2, "s": 1, "I": 1, "m": 1, "o": 3, "l": 3, "a": 1, "r": 2, "p": 1, "t": 1]
You can find any value of char how many times write in string object.
this is my solution
func hasDups(_ input: String) -> Bool {
for c in input {
if (input.firstIndex(of: c) != input.lastIndex(of: c)) {
return true
}
}
return false
}
let input = "ssaajaaan"
var count = 1
for i in 0..<input.count
{
let first = input[input.index(input.startIndex, offsetBy: i)]
if i + 1 < input.count
{
let next = input[input.index(input.startIndex, offsetBy: i + 1)]
if first == next
{
count += 1
}
else
{
count = 1
}
}
if count >= 2
{
print(first," = ",count)
}
}
let inputStr = "sakkett"
var tempStr = String()
for char in inputStr
{
if tempStr.contains(char) == false
{
tempStr = tempStr.appending(String(char))
let filterArr = inputStr.filter({ $0 == char})
if filterArr.count > 1 {
print("Duplicate char is \(char)")
}
}
}
//Output:
Duplicate char is k
Duplicate char is t

How to sort array according to number of occurrence of string?

How to sort array according to number of occurrence of string
Example :
var array = ["Hello","Me","That","Me","Hello","Me","as","the"]
and sorted array should be like this
["Me","Hello","That","as","the"]
Updated For Swift 3
var array = ["Hello","Me","That","Me","Hello","Me","as","the"]
var counts:[String:Int] = [:]
for item in array {
counts[item] = (counts[item] ?? 0) + 1
}
print(counts)
let result = counts.sorted { $0.value > $1.value }.map { $0.key }
print(result)
array.removeAll()
for string in result {
array.append(string)
}
print(array)
This is what I have been able to come up with:
var array = ["Hello","Me","That","Me","Hello","Me","as","the"]
// record the occurences of each item
var dict = [String: Int]()
for item in array {
if dict[item] == nil {
dict[item] = 1
} else {
dict[item]! += 1
}
}
// here I sort the dictionary by comparing the occurrences and map it so that the result contains only the key (the string)
let result = dict.sorted { $0.value > $1.value }.map { $0.key }
Try this -
It is tested and working as expected --
let arrayName = ["Hello","Me","That","Me","Hello","Me","as","the"]
var counts:[String:Int] = [:]
for item in arrayName {
counts[item] = (counts[item] ?? 0) + 1
}
let array = counts.keysSortedByValue(isOrderedBefore: >)
print(array) // Output - ["Me", "Hello", "the", "That", "as"]
Create Dictionary extension -
extension Dictionary {
func sortedKeys(isOrderedBefore:(Key,Key) -> Bool) -> [Key] {
return Array(self.keys).sorted(by: isOrderedBefore)
}
// Faster because of no lookups, may take more memory because of duplicating contents
func keysSortedByValue(isOrderedBefore:(Value, Value) -> Bool) -> [Key] {
return Array(self)
.sorted() {
let (_, lv) = $0
let (_, rv) = $1
return isOrderedBefore(lv, rv)
}
.map {
let (k, _) = $0
return k
}
}
}
It looks simple.
1. Take distinct from your array.
2. Make count according to distinct list.
3. Save results in collection - ie Dictionary.
4. Sort new collection.
Loop through the array and maintain a word count dictionary. Make sure the dictionary can be sorted based on values and finally obtain the set of keys and transform it back into an array.
This should work.
var array = ["Hello","Me","That","Me","Hello","Me","as","the"]
var tR : [String : Int] = [:]
let finalResult = array.reduce(tR) { result, item in
var tArr : [String: Int] = result
if let count = tArr[item] {
tArr[item] = count+1
} else {
tArr[item] = 1
}
return tArr
}
.sorted(by: { item1, item2 in
return item1.value > item2.value
}).map() { $0.key }
Please try this, hope it helps
var terms = ["Hello","Me","That","Me","Hello","Me","as","the"]
var termFrequencies = [String: Int]()
for t in terms {
if termFrequencies[t] == nil {
termFrequencies[t] = 1
} else {
termFrequencies[t] = termFrequencies[t]! + 1
}
}
for value in terms {
let index = termFrequencies[value] ?? 0
termFrequencies[value] = index + 1
}
let result = termFrequencies.sorted{$0.1 > $1.1}.map{$0.0}

Binary operator '+=' cannot be applied to two Dictionary<String, String>! operands during parsing in swift [duplicate]

Arrays in Swift support the += operator to add the contents of one Array to another. Is there an easy way to do that for a dictionary?
eg:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var combinedDict = ... (some way of combining dict1 & dict2 without looping)
You can define += operator for Dictionary, e.g.,
func += <K, V> (left: inout [K:V], right: [K:V]) {
for (k, v) in right {
left[k] = v
}
}
In Swift 4, one should use merging(_:uniquingKeysWith:):
Example:
let dictA = ["x" : 1, "y": 2, "z": 3]
let dictB = ["x" : 11, "y": 22, "w": 0]
let resultA = dictA.merging(dictB, uniquingKeysWith: { (first, _) in first })
let resultB = dictA.merging(dictB, uniquingKeysWith: { (_, last) in last })
print(resultA) // ["x": 1, "y": 2, "z": 3, "w": 0]
print(resultB) // ["x": 11, "y": 22, "z": 3, "w": 0]
Swift 4 provides merging(_:uniquingKeysWith:), so for your case:
let combinedDict = dict1.merging(dict2) { $1 }
The shorthand closure returns $1, therefore dict2's value will be used when there is a conflict with the keys.
How about
dict2.forEach { (k,v) in dict1[k] = v }
That adds all of dict2's keys and values into dict1.
Currently, looking at the Swift Standard Library Reference for Dictionary, there is no way to easy update a dictionary with another one.
You can write an extension to do it
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
extension Dictionary {
mutating func update(other:Dictionary) {
for (key,value) in other {
self.updateValue(value, forKey:key)
}
}
}
dict1.update(dict2)
// dict1 is now ["a" : "foo", "b" : "bar]
It's not built into the Swift library but you can add what you want with operator overloading, e.g:
func + <K,V>(left: Dictionary<K,V>, right: Dictionary<K,V>)
-> Dictionary<K,V>
{
var map = Dictionary<K,V>()
for (k, v) in left {
map[k] = v
}
for (k, v) in right {
map[k] = v
}
return map
}
This overloads the + operator for Dictionaries which you can now use to add dictionaries with the + operator, e.g:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var dict3 = dict1 + dict2 // ["a": "foo", "b": "bar"]
Swift 3:
extension Dictionary {
mutating func merge(with dictionary: Dictionary) {
dictionary.forEach { updateValue($1, forKey: $0) }
}
func merged(with dictionary: Dictionary) -> Dictionary {
var dict = self
dict.merge(with: dictionary)
return dict
}
}
let a = ["a":"b"]
let b = ["1":"2"]
let c = a.merged(with: b)
print(c) //["a": "b", "1": "2"]
Swift 2.0
extension Dictionary {
mutating func unionInPlace(dictionary: Dictionary) {
dictionary.forEach { self.updateValue($1, forKey: $0) }
}
func union(var dictionary: Dictionary) -> Dictionary {
dictionary.unionInPlace(self)
return dictionary
}
}
No need to have any dictionary extensions now. Swift(Xcode 9.0+) dictionary has got a functionality for this. Have a look here. Below here is an example on how to use it
var oldDictionary = ["a": 1, "b": 2]
var newDictionary = ["a": 10000, "b": 10000, "c": 4]
oldDictionary.merge(newDictionary) { (oldValue, newValue) -> Int in
// This closure return what value to consider if repeated keys are found
return newValue
}
print(oldDictionary) // Prints ["b": 10000, "a": 10000, "c": 4]
Immutable
I prefer to combine/unite immutable dictionaries with + operator so I implemented it like:
// Swift 2
func + <K,V> (left: Dictionary<K,V>, right: Dictionary<K,V>?) -> Dictionary<K,V> {
guard let right = right else { return left }
return left.reduce(right) {
var new = $0 as [K:V]
new.updateValue($1.1, forKey: $1.0)
return new
}
}
let moreAttributes: [String:AnyObject] = ["Function":"authenticate"]
let attributes: [String:AnyObject] = ["File":"Auth.swift"]
attributes + moreAttributes + nil //["Function": "authenticate", "File": "Auth.swift"]
attributes + moreAttributes //["Function": "authenticate", "File": "Auth.swift"]
attributes + nil //["File": "Auth.swift"]
Mutable
// Swift 2
func += <K,V> (inout left: Dictionary<K,V>, right: Dictionary<K,V>?) {
guard let right = right else { return }
right.forEach { key, value in
left.updateValue(value, forKey: key)
}
}
let moreAttributes: [String:AnyObject] = ["Function":"authenticate"]
var attributes: [String:AnyObject] = ["File":"Auth.swift"]
attributes += nil //["File": "Auth.swift"]
attributes += moreAttributes //["File": "Auth.swift", "Function": "authenticate"]
A more readable variant using an extension.
extension Dictionary {
func merge(dict: Dictionary<Key,Value>) -> Dictionary<Key,Value> {
var mutableCopy = self
for (key, value) in dict {
// If both dictionaries have a value for same key, the value of the other dictionary is used.
mutableCopy[key] = value
}
return mutableCopy
}
}
You can try this
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var temp = NSMutableDictionary(dictionary: dict1);
temp.addEntriesFromDictionary(dict2)
You can also use reduce to merge them. Try this in the playground
let d1 = ["a":"foo","b":"bar"]
let d2 = ["c":"car","d":"door"]
let d3 = d1.reduce(d2) { (var d, p) in
d[p.0] = p.1
return d
}
Some even more streamlined overloads for Swift 4:
extension Dictionary {
static func += (lhs: inout [Key:Value], rhs: [Key:Value]) {
lhs.merge(rhs){$1}
}
static func + (lhs: [Key:Value], rhs: [Key:Value]) -> [Key:Value] {
return lhs.merging(rhs){$1}
}
}
I recommend the SwifterSwift Library. However, if you don't want to use the entire library and all its great additions you can just make use of their extension of Dictionary:
Swift 3+
public extension Dictionary {
public static func +=(lhs: inout [Key: Value], rhs: [Key: Value]) {
rhs.forEach({ lhs[$0] = $1})
}
}
There is no need extension or any extra func anymore.
You can write like that :
firstDictionary.merge(secondDictionary) { (value1, value2) -> AnyObject in
return object2 // what you want to return if keys same.
}
You can iterate over the Key Value combinations ob the value you want to merge and add them via the updateValue(forKey:) method:
dictionaryTwo.forEach {
dictionaryOne.updateValue($1, forKey: $0)
}
Now all values of dictionaryTwo got added to dictionaryOne.
The same as #farhadf's answer but adopted for Swift 3:
let sourceDict1 = [1: "one", 2: "two"]
let sourceDict2 = [3: "three", 4: "four"]
let result = sourceDict1.reduce(sourceDict2) { (partialResult , pair) in
var partialResult = partialResult //without this line we could not modify the dictionary
partialResult[pair.0] = pair.1
return partialResult
}
Swift 3, dictionary extension:
public extension Dictionary {
public static func +=(lhs: inout Dictionary, rhs: Dictionary) {
for (k, v) in rhs {
lhs[k] = v
}
}
}
You can use,
func addAll(from: [String: Any], into: [String: Any]){
from.forEach {into[$0] = $1}
}
You can add a Dictionary extension like this:
extension Dictionary {
func mergedWith(otherDictionary: [Key: Value]) -> [Key: Value] {
var mergedDict: [Key: Value] = [:]
[self, otherDictionary].forEach { dict in
for (key, value) in dict {
mergedDict[key] = value
}
}
return mergedDict
}
}
Then usage is as simple as the following:
var dict1 = ["a" : "foo"]
var dict2 = ["b" : "bar"]
var combinedDict = dict1.mergedWith(dict2)
// => ["a": "foo", "b": "bar"]
If you prefer a framework that also includes some more handy features then checkout HandySwift. Just import it to your project and you can use the above code without adding any extensions to the project yourself.
You can use the bridgeToObjectiveC() function to make the dictionary a NSDictionary.
Will be like the following:
var dict1 = ["a":"Foo"]
var dict2 = ["b":"Boo"]
var combinedDict = dict1.bridgeToObjectiveC()
var mutiDict1 : NSMutableDictionary! = combinedDict.mutableCopy() as NSMutableDictionary
var combineDict2 = dict2.bridgeToObjectiveC()
var combine = mutiDict1.addEntriesFromDictionary(combineDict2)
Then you can convert the NSDictionary(combine) back or do whatever.
import Foundation
let x = ["a":1]
let y = ["b":2]
let out = NSMutableDictionary(dictionary: x)
out.addEntriesFromDictionary(y)
The result is an NSMutableDictionary not a Swift typed dictionary, but the syntax to use it is the same (out["a"] == 1 in this case) so you'd only have a problem if you're using third-party code which expects a Swift dictionary, or really need the type checking.
The short answer here is that you actually do have to loop. Even if you're not entering it explicitly, that's what the method you're calling (addEntriesFromDictionary: here) will do. I'd suggest if you're a bit unclear on why that would be the case you should consider how you would merge the leaf nodes of two B-trees.
If you really actually need a Swift native dictionary type in return, I'd suggest:
let x = ["a":1]
let y = ["b":2]
var out = x
for (k, v) in y {
out[k] = v
}
The downside of this approach is that the dictionary index - however it's done - may be rebuilt several times in the loop, so in practice this is about 10x slower than the NSMutableDictionary approach.
All of these responses are complicated. This is my solution for swift 2.2 :
//get first dictionnary
let finalDictionnary : NSMutableDictionary = self.getBasicDict()
//cast second dictionnary as [NSObject : AnyObject]
let secondDictionnary : [NSObject : AnyObject] = self.getOtherDict() as [NSObject : AnyObject]
//merge dictionnary into the first one
finalDictionnary.addEntriesFromDictionary(secondDictionnary)
My needs were different, I needed to merge incomplete nested data sets without clobbering.
merging:
["b": [1, 2], "s": Set([5, 6]), "a": 1, "d": ["x": 2]]
with
["b": [3, 4], "s": Set([6, 7]), "a": 2, "d": ["y": 4]]
yields:
["b": [1, 2, 3, 4], "s": Set([5, 6, 7]), "a": 2, "d": ["y": 4, "x": 2]]
This was harder than I wanted it to be. The challenge was in mapping from dynamic typing to static typing, and I used protocols to solve this.
Also worthy of note is that when you use the dictionary literal syntax, you actually get the foundation types, which do not pick up the protocol extensions. I aborted my efforts to support those as I couldn't find an easy to to validate the uniformity of the collection elements.
import UIKit
private protocol Mergable {
func mergeWithSame<T>(right: T) -> T?
}
public extension Dictionary {
/**
Merge Dictionaries
- Parameter left: Dictionary to update
- Parameter right: Source dictionary with values to be merged
- Returns: Merged dictionay
*/
func merge(right:Dictionary) -> Dictionary {
var merged = self
for (k, rv) in right {
// case of existing left value
if let lv = self[k] {
if let lv = lv as? Mergable where lv.dynamicType == rv.dynamicType {
let m = lv.mergeWithSame(rv)
merged[k] = m
}
else if lv is Mergable {
assert(false, "Expected common type for matching keys!")
}
else if !(lv is Mergable), let _ = lv as? NSArray {
assert(false, "Dictionary literals use incompatible Foundation Types")
}
else if !(lv is Mergable), let _ = lv as? NSDictionary {
assert(false, "Dictionary literals use incompatible Foundation Types")
}
else {
merged[k] = rv
}
}
// case of no existing value
else {
merged[k] = rv
}
}
return merged
}
}
extension Array: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Array {
return (self + right) as? T
}
assert(false)
return nil
}
}
extension Dictionary: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Dictionary {
return self.merge(right) as? T
}
assert(false)
return nil
}
}
extension Set: Mergable {
func mergeWithSame<T>(right: T) -> T? {
if let right = right as? Set {
return self.union(right) as? T
}
assert(false)
return nil
}
}
var dsa12 = Dictionary<String, Any>()
dsa12["a"] = 1
dsa12["b"] = [1, 2]
dsa12["s"] = Set([5, 6])
dsa12["d"] = ["c":5, "x": 2]
var dsa34 = Dictionary<String, Any>()
dsa34["a"] = 2
dsa34["b"] = [3, 4]
dsa34["s"] = Set([6, 7])
dsa34["d"] = ["c":-5, "y": 4]
//let dsa2 = ["a": 1, "b":a34]
let mdsa3 = dsa12.merge(dsa34)
print("merging:\n\t\(dsa12)\nwith\n\t\(dsa34) \nyields: \n\t\(mdsa3)")
Swift 2.2
func + <K,V>(left: [K : V], right: [K : V]) -> [K : V] {
var result = [K:V]()
for (key,value) in left {
result[key] = value
}
for (key,value) in right {
result[key] = value
}
return result
}
I would just use the Dollar library.
https://github.com/ankurp/Dollar/#merge---merge-1
Merges all of the dictionaries together and the latter dictionary overrides the value at a given key
let dict: Dictionary<String, Int> = ["Dog": 1, "Cat": 2]
let dict2: Dictionary<String, Int> = ["Cow": 3]
let dict3: Dictionary<String, Int> = ["Sheep": 4]
$.merge(dict, dict2, dict3)
=> ["Dog": 1, "Cat": 2, "Cow": 3, "Sheep": 4]
Here is a nice extension I wrote...
extension Dictionary where Value: Any {
public func mergeOnto(target: [Key: Value]?) -> [Key: Value] {
guard let target = target else { return self }
return self.merging(target) { current, _ in current }
}
}
to use:
var dict1 = ["cat": 5, "dog": 6]
var dict2 = ["dog": 9, "rodent": 10]
dict1 = dict1.mergeOnto(target: dict2)
Then, dict1 will be modified to
["cat": 5, "dog": 6, "rodent": 10]