Make statement more clear: checking object for key in dictionary - swift

I have dictionary of type - [String : [MyClass]].
I have array of type MyClass, what i want is to check, whether my dictionary contain array of MyClass object for specific key. If it does, it append element to array, if not, it create new array with single element MyClass. I ended up with:
for item in items{
if let _ = dict[key] {
// Add operations if corresponding array exist
dict[key]?.append(item)
} else {
// Create array if need
dict[key] = [item]
}
}
it work but look kind of ugly, and i use optional binding for check whether array exist, but not use the result (wildcard pattern _).
Is there anyway to make that code look shorter and cleaner? Thanks.

First, you can test and get an existing value with optional binding,
and then append (or set) all new items:
if let oldItems = dict[key] {
dict[key] = oldItems + items
} else {
dict[key] = items
}
This can be simplified with the nil-coalescing operator ??:
dict[key] = (dict[key] ?? []) + items
In Swift 4 you can simply use the subscript method with a default value:
dict[key, default: []] += items
// Or:
dict[key, default: []].append(contentsOf: items)
Self-contained example:
var dict = ["foo": [1, 2, 3]]
dict["foo", default: []] += [4, 5]
dict["bar", default: []] += [6,7]
print(dict) // ["bar": [6, 7], "foo": [1, 2, 3, 4, 5]]

You can use the following implementation to avoid wildCart pattern :
import Foundation
class MyClass { }
class Apple : MyClass { }
class Ant : MyClass { }
class Ambulance : MyClass { }
class Test {
var dictionary : [String : [MyClass.Type]] = [:]
let items : [MyClass.Type] = [Apple.self, Ant.self, Ambulance.self]
let key = "a"
public func insert(key : String, items : [MyClass.Type] ) {
guard !items.isEmpty else { return }
items.forEach { (item) in
if dictionary[key] == nil {
dictionary[key] = [item]
} else {
dictionary[key]?.append(item)
}
}
}
}
let test = Test()
test.insert(key: test.key, items: test.items)
print(test.dictionary)
Output :
["a": [__lldb_expr_27.Apple, __lldb_expr_27.Ant, __lldb_expr_27.Ambulance]]

Related

How do i fix mutating operator isn't mutable error?

I'm trying to modify a dictionary containing a string as the key and an integer as the value. However, when I try to add/minus 1 from the integer, it returns me that error. currCleanup is a Cleanup object, which are clean up sessions people can host. items_collected is a dictionary within a Cleanup object.
#Published var firestore = Firestore.firestore()
#Published var errorMessage: String = ""
#Published private(set) var cleanups: [Cleanup] = []
#Published var currCleanup: Cleanup
//the functions with the error
func addOneItem(itemName: String)
{
for (nam, num) in currCleanup.items_collected {
if nam == itemName {
num += 1 //this is where the error occurs
}
}
db.collection("Cleanups").document(currCleanup.username).updateData(["itemsCollected" : currCleanup.items_collected])
}
func delOneItem(itemName: String)
{
for (nam, num) in currCleanup.items_collected
{
if nam == itemName {
num -= 1 //here too
}
}
db.collection("Cleanups").document(currCleanup.username).updateData(["itemsCollected" : currCleanup.items_collected])
}
When you iterate over value objects, you don't receive a reference to their values, but rather new variables, where the value is copied to.
In your code, num is not a reference to the dictionary value, but a totally new variable. Even if you add var before (nam, num), it won't work: You'll only change the value of the variable num, but not the stored-in-dictionary value. Consider this example:
var dict = ["One" : 1,
"Two" : 2,
"Three" : 3]
let keyToChange = "Two"
for var (key, value) in dict {
if key == keyToChange {
value = 4
}
}
print(dict) // ["Two": 2, "Three": 3, "One": 1]
You need to access the dictionary value directly in order to change it:
var dict = ["One" : 1,
"Two" : 2,
"Three" : 3]
let keyToChange = "Two"
for (key, value) in dict {
if key == keyToChange {
dict[key] = 4
}
}
print(dict) // ["Two": 4, "Three": 3, "One": 1]
On the other hand, there's no point in loop, you can just check whether the key exists and change its value directly:
var dict = ["One" : 1,
"Two" : 2,
"Three" : 3]
let keyToChange = "Two"
if dict[keyToChange] != nil {
dict[keyToChange] = 4
}
print(dict) // ["Two": 4, "One": 1, "Three": 3]
In your code it could be this:
if let value = currCleanup.items_collected[itemName] {
currCleanup.items_collected[itemName] = value + 1
}
Instead of this:
for (nam, num) in currCleanup.items_collected {
if nam == itemName {
num += 1 //this is where the error occurs
}
}
to increment your array of values at the given itemName, try this approach:
func addOneItem(itemName: String) {
if currCleanup.items_collected[itemName] != nil {
currCleanup.items_collected[itemName] = currCleanup.items_collected[itemName]! + 1
db.collection("Cleanups").document(currCleanup.username).updateData(["itemsCollected" : currCleanup.items_collected])
}
}
Similarly for delOneItem

Is it possible to have a range as a key in a Swift Dictionary?

For simplification. Lets say i have some unique values -> the numbers from 1 to 10
Now I want 1-5 map to the value "first" and I want 6-10 map to the value "second"
Is there a way I can create or extend a dictionary to work like the following?
let dict: [Range<Int> : String]
The goal is to have the following results:
print(dict[1]) // prints first
print(dict[2]) // prints first
print(dict[3]) // prints first
print(dict[7]) // prints second
print(dict[8]) // prints second
print(dict[9]) // prints second
The way I am currently doing it is to simply have the multiple keys map to the same value. But my dictionary can have sometimes 60k values. So I am wondering if a range can work.
I know I can make the value into a class instead of a struct so that multiple keys can map to the same class object, but I was wondering if simply creating a Dictionary that worked like above was possible?
If you insist on using Dictionary, you have to wait until Swift 3.1 (currently in beta):
extension CountableClosedRange : Hashable {
public var hashValue: Int {
return "\(lowerBound) to \(upperBound)".hashValue
}
}
// This feature is called concrete-type extension and requires Swift 3.1
extension Dictionary where Key == CountableClosedRange<Int> {
subscript(rawValue rawValue: Int) -> Value? {
for k in self.keys {
if k ~= rawValue {
return self[k]
}
}
return nil
}
}
let dict : [CountableClosedRange<Int>: String] = [
1...5: "first",
6...10: "second"
]
print(dict[rawValue: 1])
print(dict[rawValue: 2])
print(dict[rawValue: 3])
print(dict[rawValue: 7])
print(dict[rawValue: 8])
print(dict[rawValue: 9])
However, it's a lot clearer if you implement your own data model:
struct MyRange {
var ranges = [CountableClosedRange<Int>]()
var descriptions = [String]()
mutating func append(range: CountableClosedRange<Int>, description: String) {
// You can check for overlapping range here if you want
self.ranges.append(range)
self.descriptions.append(description)
}
subscript(value: Int) -> String? {
for (i, range) in self.ranges.enumerated() {
if range ~= value {
return descriptions[i]
}
}
return nil
}
}
var range = MyRange()
range.append(range: 1...5, description: "one")
range.append(range: 6...10, description: "second")
print(range[1])
print(range[2])
print(range[6])
print(range[7])
print(range[100])
This is in Swift 3.0, it may not be as nice as Code Different's answer though.
class MyRange: Hashable, Equatable {
public var hashValue: Int {
get {
return (self.range.lowerBound + self.range.upperBound).hashValue
}
}
var range: Range<Int>!
public static func ==(_ lhs: MyRange, _ rhs: MyRange) -> Bool {
return lhs.range == rhs.range
}
init(range: Range<Int>) {
self.range = range
}
}
extension Dictionary where Key: MyRange, Value: ExpressibleByStringLiteral {
internal subscript(index: Int) -> [String] {
return self.filter({$0.key.range.contains(index)}).map({$0.value as! String})
}
}
Now, you can make your dictionary like so:
var dict = Dictionary<MyRange, String>()
dict[MyRange(range: 0..<5)] = "first"
dict[MyRange(range: 5..<10)] = "second"
Getting values works with Integers and Ranges:
print(dict[1]) // ["first"]
print(dict[5]) // ["second"]
print(dict[11]) // []
print(dict[MyRange(range: 0..<5)]) // "first"
print(dict[MyRange(range: 0..<6)]) // nil
The dictionary should look like this:
print(dict)
// [MyRange: "first", MyRange: "second"]

Transforming [String : String] to [String : URL] and flattening out nil values

Say I have a dictionary of type [String : String] which I want to transform to type [String : URL]. I can use map or flatMap to transform the dictionary, but due to the failable URL(string:) initializer, my values are optional:
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com"]
let result = source.flatMap { ($0, URL(string: $1)) }
This returns a value of type [(String, URL?)] and not [String : URL]. Is there a one-liner to transform this dictionary with a single method? My first thought was something like:
source.filter { $1 != nil }.flatMap { ($0, URL(string: $1)!) }
But I don't need to check if the value is nil (values will never return nil on a dictionary concrete values), I need to check if the return value of URL(string:) is nil.
I could use filter to remove the nil values, but this doesn't change the return type:
source.flatMap { ($0, URL(string: $1)) }.filter { $1 != nil }
You need to make sure you're returning tuples with only non-optional values, and since optional values themselves support flatMap you can use that to make the tuple optional as opposed to the individual value inside of it:
let source = [
"google": "http://google.com",
"twitter": "http://twitter.com",
"bad": "",
]
var dict = [String: URL]()
source.flatMap { k, v in URL(string: v).flatMap { (k, $0) } }.forEach { dict[$0.0] = $0.1 }
But since we've already expanded out the dictionary creation (I don't think there's a built-in way to create a dict from an array), you might as well do this:
var dict = [String: URL]()
source.forEach { if let u = URL(string: $1) { dict[$0] = u } }
Here are a few solutions:
//: Playground - noun: a place where people can play
import Foundation
let source = ["google": "http://google.com", "twitter": "http://twitter.com", "bad": ""]
//: The first solution takes advantage of the fact that flatMap, map and filter can all be implemented in terms of reduce.
extension Dictionary {
/// An immutable version of update. Returns a new dictionary containing self's values and the key/value passed in.
func updatedValue(_ value: Value, forKey key: Key) -> Dictionary<Key, Value> {
var result = self
result[key] = value
return result
}
}
let result = source.reduce([String: URL]()) { result, item in
guard let url = URL(string: item.value) else { return result }
return result.updatedValue(url, forKey: item.key)
}
print(result)
//: This soultion uses a custom Dictionary initializer that consums the Key/Value tuple.
extension Dictionary {
// construct a dictionary from an array of key/value pairs.
init(items: [(key: Key, value: Value)]) {
self.init()
for item in items {
self[item.key] = item.value
}
}
}
let items = source
.map { ($0, URL(string: $1)) } // convert the values into URL?s
.filter { $1 != nil } // filter out the ones that didn't convert
.map { ($0, $1!) } // force unwrap the ones that did.
let result2 = Dictionary(items: items)
print(result2)
//: This solution also uses the above initializer. Since unwrapping optional values is likely a common thing to do, this solution provides a method that takes care of the unwrapping.
protocol OptionalType {
associatedtype Wrapped
var asOptional : Wrapped? { get }
}
extension Optional : OptionalType {
var asOptional : Wrapped? {
return self
}
}
extension Dictionary where Value: OptionalType {
// Flatten [Key: Optional<Type>] to [Key: Type]
func flattenValues() -> Dictionary<Key, Value.Wrapped> {
let items = self.filter { $1.asOptional != nil }.map { ($0, $1.asOptional!) }
return Dictionary<Key, Value.Wrapped>(items: items)
}
}
let result3 = Dictionary(items: source.map { ($0, URL(string: $1)) }).flattenValues()
print(result3)
Daniel T's last solution is quite nice if you want to write it in a more functional style. I'd do it a bit differently with the primary difference being a method to turn a tuple of optionals into an optional tuple. I find that to be a generally useful transform, especially combined with flatMap.
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com", "fail" : ""]
// Dictionary from array of (key, value) tuples. This really ought to be built it
extension Dictionary {
public init(_ array: [Element]) {
self.init()
array.forEach { self[$0.key] = $0.value }
}
}
//Turn a tuple of optionals into an optional tuple. Note will coerce non-optionals so works on (A, B?) or (A?, B) Usefull to have variants for 2,3,4 tuples.
func raiseOptionality<A,B>(_ tuple:(A?, B?)) -> (A, B)? {
guard let a = tuple.0, let b = tuple.1 else { return nil }
return (a,b)
}
let result = Dictionary(source.flatMap { raiseOptionality(($0, URL(string: $1))) } )
Easy as pie if you just want a good, known URL in place of the bad ones.
Use
let source = ["google" : "http://google.com", "twitter" : "http://twitter.com", "bad": ""]
let defaultURL = URL(string: "http://www.google.com")! // or whatever you want for your default URL
let result = source.flatMap { ($0, URL(string: $1) ?? defaultURL) }

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]

Swift arrays and contains, how to determine if a collection contains an object or value?

I'm at it again with swift arrays and containsObject provided by NSArray only!
I bridge the swift array to NSArray to do that contains:
extension Array {
func contains(object:AnyObject!) -> Bool {
if(self.isEmpty) {
return false
}
let array: NSArray = self.bridgeToObjectiveC();
return array.containsObject(object)
}
}
it works fine in general but as soon as I put a String! in an array of type String, it crashes. Even though containsObject does take a AnyObject!
var str : String! = "bla"
var c = Array<String>();
c.append(str)
println(c.contains(str))
declaring a String! array also doesn't help
var str : String! = "bla"
var c = Array<String!>();
c.append(str)
println(c.contains(str))
BUT the same without ! works fine
var str : String = "bla"
var c = Array<String>();
c.append(str)
println(c.contains(str))
SO how do I explicitly wrap stuff? I don't really see why I'd have to explicitly wrap it only so it is right unwrapped but that's what it looks like.
Swift 1:
let array = ["1", "2", "3"]
let contained = contains(array, "2")
println(contained ? "yes" : "no")
Swift 2, 3, 4:
let array = ["1", "2", "3"]
let contained = array.contains("2")
print(contained ? "yes" : "no")
Swift
If you are not using object then you can user this code for contains.
let elements = [ 10, 20, 30, 40, 50]
if elements.contains(50) {
print("true")
}
If you are using NSObject Class in swift. This variables is according to my requirement. you can modify for your requirement.
var cliectScreenList = [ATModelLeadInfo]()
var cliectScreenSelectedObject: ATModelLeadInfo!
This is for a same data type.
{ $0.user_id == cliectScreenSelectedObject.user_id }
If you want to AnyObject type.
{ "\($0.user_id)" == "\(cliectScreenSelectedObject.user_id)" }
Full condition
if cliectScreenSelected.contains( { $0.user_id == cliectScreenSelectedObject.user_id } ) == false {
cliectScreenSelected.append(cliectScreenSelectedObject)
print("Object Added")
} else {
print("Object already exists")
}
Generally, when you want to have an array that contains a custom object or struct, and you want to work with "contains" function, your class or struct should be conformed to "Equatable" protocol and you should implement the "==" function for later comparisons...
struct booy: Equatable{
static func == (lhs: booy, rhs: booy) -> Bool {
return lhs.name == rhs.name
}
var name = "abud"
}
let booy1 = booy(name: "ali")
let booy2 = booy(name: "ghasem")
var array1 = [booy]()
array1.append(booy1)
array1.append(booy2)
let booy3 = booy(name: "ali")
if array1.contains(booy3){
print("yes") }