how to check if a key equal a value in swift dictionary? - swift

let say I have this dictionary
var myDic = ["Item" : " Item1", "Item2" : " Item3"]
how can I write an if statement to check if Item and Item1 are a key-value paire?

According to the https://developer.apple.com/documentation/swift/dictionary
Every dictionary is an unordered collection of key-value pairs. You
can iterate over a dictionary using a for-in loop, decomposing each
key-value pair into the elements of a tuple.
This means you can write the following code:
let myDict = ["Item" : " Item1", "Item2" : " Item3"]
for (key, val) in myDict {
if (key == "Item2" && val == " Item3") {
print("match!") //prints match!
}
}
This is obviously kind of a "naive" approach where the values are hardcoded in the if-statement. A one-line alternative:
print(myDict.contains(where: { $0.key == "Item2" && $0.value == " Item3" })) //true
Let's say you need to check for two pairs. Then you can use KeyValuePairs which preserves the order and simply iterate:
let toFind: KeyValuePairs = [ "Item2" : " Item3", "Itemx" : " Item4"]
for tup in toFind {
print(myDict.contains(where: { $0 == tup })) //true, false
}
If you want to follow this approach, I recommend reading about the important differences between Dictionary and KeyValuePairs https://developer.apple.com/documentation/swift/keyvaluepairs

Related

Removing Non Duplicate Keys from Two Dictionary

I have two dictionaries in Swift with few similar values which are in dynamic mode:
dict1 = ["a1":"value 1", "b1":"value2", "c1":"value 3"]
dict2 = ["b1": "value2", "d1": "value4"]
If I want to compare these two dictionaries and want to extract only the matching keys even nested, how do I about to do that?
If you want the common keys with the value in one of them :
let intersectionDict = dict1.filter { dict2.keys.contains($0.key) }
//Or
let intersectionDict2 = dict2.filter { dict1.keys.contains($0.key) }
If you want the values to match too:
let intersectionDict3 = dict1.filter { dict2[$0.key] == $0.value }
And the result is:
print(intersectionDict3) //["b1": "value2"]
As others have shown, you can do this using a filter statement. You can make it even quicker by always filtering the smaller of the two dicts, improving the time complexity from O(dict1.size) to O(min(dict1.size, dict2.size).
extension Dictionary {
func intersectingByKeys(with other: Dictionary) -> Dictionary {
let (smallerDict, largerDict) = (self.count < other.count) ? (self, other) : (other, self)
return smallerDict.filter { key, _ in largerDict.keys.contains(key) }
}
}
let dict1 = ["a1":"value 1", "b1":"value2", "c1":"value 3"]
let dict2 = ["b1": "value2", "d1": "value4"]
print(dict1.intersectingByKeys(with: dict2))
You can create a Set from the keys of one of the dictionaries and call intersection on the Set with the keys of the other dictionary.
let matchingKeys = Set(dict1.keys).intersection(dict2.keys) // {"b1"}

How to get last entered value in a Dictionary in Swift?

How do I get the last entered value in a Dictionary in Swift? For example how would I get the value "CCC" from below:
var dictionary = Dictionary<String, String>()
dictionary.updateValue("AAA", forKey: "111")
dictionary.updateValue("BBB", forKey: "222")
dictionary.updateValue("CCC", forKey: "333")
What you are after is generally known as a Ordered Dictionary, i.e. a dictionary that remembers the order that items have been added. A quick Google search turns up a GitHub project that may suit you.
https://github.com/lukaskubanek/OrderedDictionary
With this as the type of your dictionary, you could just use:
dictionary.last // returns Optional(("CCC", "333"))
The GitHub page has details on how you would go about adding this class to your project.
If your key is sorted you can try:
var dictionary = Dictionary<String, String>()
dictionary.updateValue("AAA", forKey: "111")
dictionary.updateValue("BBB", forKey: "222")
dictionary.updateValue("CCC", forKey: "333")
print(dictionary.keys.sorted().last.map({ ($0, dictionary[$0]!) }))
The whole point of dictionaries is they're NOT ordered. This is why their lookups are generally so fast is because they partition elements without regard for their order.
If you want items in a particular order, you should use an array. Yes, "sorted dictionaries" exist, but they're really just dictionary-like interfaces on top of arrays. They contain none of the benefits that traditional dictionaries bring.
If you think you need an ordered dictionary, you probably need to consider a new structure for your data.
//If you need to build a query string for http:
let httpBody:[String : String] = [
"Street" : "1234 W 1st Street",
"Building" : "Suite 500",
"City" : "Los Angeles",
"State" : "CA",
"Zip" : "92005"
]
var idx = 0
var queryStr = ""
for (k, v) in httpBody {
if idx == httpBody.count - 1 {
queryStr += k + "=" + v
} else {
queryStr += k + "=" + v + "&"
idx += 1
}
}
print(queryStr)
//Example: for some REST API
//let bodyData:Data = queryStr.data(using: .utf8)!
//request.httpBody = bodyData
//Or this option:
var newStr = ""
for (k, v) in httpBody {
let index = httpBody.index(httpBody.startIndex, offsetBy: httpBody.count - 1)
if k == httpBody.keys[index] {
newStr += k + "=" + v
} else {
newStr += k + "=" + v + "&"
}
}
print( "\n", newStr)

Sorted associative array swift 3.0 [duplicate]

I know that this topic has been already discussed but I can't solve looking other answers, so sorry in advance for my ripetion!
I need to sort this Dictionary by keys
codeValueDict = ["us": "$", "it": "€", "fr": "€"]
so I need a dictionary like this
sortedDict = ["fr": "€", "it": "€", "us": "$"]
but I can't do that.
I tried this
let sortedKeysAndValues = sorted(dictionary) { $0.0 < $1.0 }
but after I need to create two arrays from this dictionary (keys and values) and, using that solution
codesArray = sortedKeysAndValues.keys.array
give me the error '[(String, String)]' does not have a member named 'keys' because that solution doesn't return exactly a dictionary.
So i tried another solution:
let prova = codiceNomeDict as NSDictionary
for (k,v) in (Array(codiceNomeDict).sorted {$0.1 < $1.1}) {
let value = "[\"\(k)\": \"\(v)\"]"
println(value)
}
Which works good but then I don't know how create a new dictionary of values.
What's the best solution? How to make it works?
The output of sorted function above is an Array. So you cannot get keys & values like a Dictionary. But you can use map function to retrieve those sorted keys & values
Return an Array containing the sorted elements of source{according}.
The sorting algorithm is not stable (can change the relative order of
elements for which isOrderedBefore does not establish an order).
let codeValueDict = ["us": "$", "it": "€", "fr": "€"]
let sortedArray = sorted(codeValueDict, {$0.0 < $1.0})
print(sortedArray)
let keys = sortedArray.map {return $0.0 }
print(keys)
let values = sortedArray.map {return $0.1 }
print(values)
Dictionaries are not ordered. If you want to enumerate over them in order, you can do that using #HoaParis's solution (which is my preference), or also
for (k,v) in sorted(codiceNomeDict, {$0.1 < $1.1}) { ... }
which is just a little better way than what you were doing before because it doesn't generate a temporary array.
But if you really want "a collection that maps one value to another and is ordered by its key" then you need to create some other data structure for that. So let's do that. It's a good learning experience.
This version just implements SequenceType and provides a get/set subscript, which is most of what you'd generally want. Making it a full CollectionType is a bit of a pain I think, since startIndex and endIndex hae to be O(1). Possible; just more than I want to do this morning.
Note the major addition of Key: Comparable. That's why Dictionary can't be ordered. There's no promise that you can sort their keys. By adding that requirement, we can.
struct SortedDictionary<Key: Hashable, Value where Key: Comparable>: SequenceType {
private var dict: Dictionary<Key, Value>
init(_ dict: Dictionary<Key, Value>) {
self.dict = dict
}
func generate() -> GeneratorOf<(Key, Value)> {
let values = Array(zip(self.dict.keys, self.dict.values))
.sorted {$0.0 < $1.0 }
return GeneratorOf(values.generate())
}
subscript(key: Key) -> Value? {
get { return self.dict[key] }
set(value) { self.dict[key] = value }
}
}
var codeValueDict = ["us": "$", "it": "€", "fr": "€"]
var sortedDict = SortedDictionary(codeValueDict)
for (k, v) in sortedDict {
println("\(k) => \(v)")
}
sortedDict["us"]
sortedDict["ab"] = "!"
sortedDict
Why would you bother with SortedDictionary when you already have sorted()? Well, usually I wouldn't. But it does offer opportunities for abstraction. You could control sort order at object creation rather than at object enumeration. You could potentially cache the sort order (though I suspect in most cases that will hurt rather than help).
But I recommend just using sorted in general.
Swift doesn't include a sorted dictionary type, and dictionaries cannot be sorted. You could add an extension that offers sorting to [(Key, Value)] by doing this:
extension Dictionary {
func sort(isOrderedBefore: (Key, Key) -> Bool) -> [(Key, Value)] {
var result: [(Key, Value)] = []
let sortedKeys = keys.array.sorted(isOrderedBefore)
for key in sortedKeys {
result.append(key, self[key]!)
}
return result
}
}
Sorting your keys by the dictionary's value is actually simpler than it appears at first:
let yourDict = ["One": "X", "Two": "B", "Three": "Z", "Four": "A"]
let sortedKeys = yourDict.keys.sort({ (firstKey, secondKey) -> Bool in
return yourDict[firstKey] < yourDict[secondKey]
})
And that's it! There's really nothing more to it.
You can't sort dictionary in such easy way. I think dictionary is using some sort of tree data structure. But after sorting you get an array of tuples. So you can get keys in such way:
let codeValueDict = ["us": "$", "it": "€", "fr": "€"]
let sortedKeysAndValues = sorted(codeValueDict) { $0.0 < $1.0 }
let keys = sortedKeysAndValues.map {$0.0 }
let values = sortedKeysAndValues.map {$0.1 }
Sort keys case-insensitive in Swift 2
Here is a function which returns a case-insensitive sorted array of keys (or any String values).
Please keep in mind that Swift’s dictionary data structure can not be stored sorted by keys in memory. So yes, you can sort it by keys but if you print it for example then the key order is again random.
/// returns an array of values sorted by values case-insensitive
func sortCaseInsensitive(values:[String]) -> [String]{
let sortedValues = values.sort({ (value1, value2) -> Bool in
if (value1.lowercaseString < value2.lowercaseString) {
return true
} else {
return false
}
})
return sortedValues
}
Call with
let dict = ["world": "Hello!", "foo": "bar", "zYeah": "a", "akey": "xval"]
let sortedKeys = sortCaseInsensitive(Array(dict.keys))

Swift Dictionary: join key and value into string

I'm looking for a best syntax for this:
let responseParameters = ["keyA" : "valueA", "keyB" : "valueB"]
var responseString = ""
for (key, value) in responseParameters {
responseString += "\(key):\(value)"
if Array(responseParameters.keys).last != key {
responseString += "+"
}
}
//responseString: keyA:valueA+keyB:valueB
Something like an array joinWithSeparator, using a flatMap or something like that. (study purpose)
You can map over key/value pairs in dictionaries to convert them to an Array of Strings, then you can join those with +. But remember, dictionaries are unordered, so this will not preserve the input ordering.
let responseParameters = ["keyA" : "valueA", "keyB" : "valueB"]
let responseString = responseParameters.map{ "\($0):\($1)" }
.joined(separator: "+")
A dictionary is not an ordered collection, so you'll have to sort the keys prior to accessing the "ordered version" of the key-value pairs. E.g.
let responseParameters = ["keyA" : "valueA", "keyB" : "valueB", "keyC" : "valueC"]
let responseString = responseParameters
.sort { $0.0 < $1.0 }
.map { $0 + ":" + $1 }
.joinWithSeparator("+")
print(responseString) // keyA:valueA+keyB:valueB+keyC:valueC
Updated answer for swift 5 :
let responseParameters = ["keyA": "valueA", "keyB": "valueB"]
let responseString = responseParameters.map { "\($0):\($1)" }
.joined(separator: "+")
Actually, you can use reduce like: 🙌
let responseParameters = ["keyA": "valueA", "keyB": "valueB"]
let responseString = responseParameters.reduce("") { $0.isEmpty ? "\($1.key):\($1.value)" : "\($0)+\($1.key):\($1.value)" }

Looping through a dictionary and checking each value type

How do I loop through a dictionary and check for each items value type?
Example dictionary:
var dict = ([
"a number" : 1,
"a boolean" : false,
"a string" : "Hello"
])
My attempts at checking for values:
for item in dict.1 {
if let current = item as? NSNumber {
print(current)
}
}
and I tried this:
for item in settings {
if item[1] == item[1] as NSNumber {
print(item)
}
}
Important note:
As #Leo pointed out, it's important to keep track of what your dictionary's value type is while comparing. The dictionary that I included as my example would be of type [String : NSObject] and the dictionary in my project was of type [String : NSNumber]. They have to be approached differently!
You can use is in swift
var dict = ([
"a number" : 1,
"a boolean" : false,
"a string" : "Hello"
])
for (key,value) in dict{
if value is String{
println(value)
}
}
Also you can get className
for (key,value) in dict{
println(String.fromCString(object_getClassName(value)))
}
This will log
Optional("__NSCFString")
Optional("__NSCFNumber")
Optional("__NSCFBoolean")
Update:
Swift is a type safe language,so if you have a dictionary like this
var dict = ([
"a number" : 1,
"a boolean" : false,
])
The dict is type of [String : NSNumber],so you do not need to check.
But,if you have a dictionary like this
var dict = ([
"a number" : 1,
"a boolean" : false,
"a string" : "Hello"
])
Then dict is type of [String:NSObject],in this case you need to check type.
Update,check if it is Int or Bool
Better to declare your dictionary to [String:Any]
Then
var dict:[String:Any] = ([
"a number" : 1,
"a boolean" : false,
])
for (key,value) in dict{
if value is Bool{
println(value)
}
if value is Int{
println(value)
}
}
From the swift reference, here is how to iterate over a dictionary
Iterating Over a Dictionary
You can iterate over the key-value pairs in a dictionary with a for-in
loop. Each item in the dictionary is returned as a (key, value) tuple,
and you can decompose the tuple’s members into temporary constants or
variables as part of the iteration:
for (airportCode, airportName) in airports {
println("\(airportCode): \(airportName)")
}
// YYZ: Toronto Pearson
// LHR: London Heathrow
So this should work for your example.
var dict = ([
"a number" : 1,
"a boolean" : false,
"a string" : "Hello"
])
for (k,v) in dict {
if let x = v as? NSNumber {
println("x = \(x)")
}
}
You can also use dynamicType to find the class, then use a simple switch statement to take the appropriate action(s)
var dict = ([
"a number" : 1,
"a boolean" : false,
"astring" : "Hello"
])
for (k,v) in dict {
switch "\(v.dynamicType)" {
case "__NSCFString":
println("found String = \(v)")
case "__NSCFBoolean":
println("found Boolean = \(v as! Bool)")
case "__NSCFNumber":
println("found Number = \(v)")
default:break
}
}
For those who are having issues with warnings, make sure you check your type as #Leo stated above. If your value type is of NSNumber, you'll get errors. If it's of type NSObject use #Leo's or #nPn's answers.
This is working for me in my project which has a value type of NSNumber:
for (key, value) in settings {
if value == value as Bool {
print(value)
}
if value == value as NSNumber {
print(value)
}
}