G'day,
I'm trying to use a for loop to access the values for the same key within an array of dictionaries in Swift.
For example,
let dictionaryOne = [
"name": "Peter",
"age": "42",
"location": "Milwaukee"]
let dictionaryTwo = [
"name": "Paul",
"age": "89",
"location": "Denver"]
let arrayOfDictionaries = [dictionaryOne, dictionaryTwo]
I'm attempting to create a function using a for loop that will output an array containing the values for location i.e. ["Milwaukee", "Denver"]
I have looked at other responses but I can only find how to access the value for "location" straight from the dictionary itself, which would be cumbersome if there were many different dictionaries rather than just two.
Many thanks for any help you can provide!
You can take advantage of the map method, whose purpose is to loop through the array and transform each element into another type:
arrayOfDictionaries.map { (dict: [String : String]) -> String? in
return dict["location"]
}
The closure passed to the map receives an array element, and returns the transformed value - in your case, it retrieves and returns the value for the location key.
You can also use the compact form:
arrayOfDictionaries.map { $0["location"] }
Note that this method returns an array of optional strings, because the dictionary subscript operator always returns an optional. If you need an array of non optionals, then this is the unsafe version:
let x = arrayOfDictionaries.map { $0["location"]! }
Of course if the value for "location" key doesn't exist for an array element, a runtime exception will be raised.
More info about map at the Swift Standard Template Library
The way I see it, you would populate a new array of Strings from the cities listed before.
var locations = [String]()
for dictionary in arrayOfDictionaries{
locations.append(dictionary["location"]!)
}
println(locations)
There are a few ways you could do this. One is to use key-value coding (KVC):
let locations = (arrayOfDictionaries as NSArray).valueForKey("location") as [String]
Related
I have an array that is storing a large number of various names in string format. There can be duplicates.
let myArray = ["Jim","Tristan","Robert","Lexi","Michael","Robert","Jim"]
In this case I do NOT know what values will be in the array after grabbing the data from a parse server. So the data imported will be different every time. Just a list of random names.
Assuming I don't know all the strings in the array I need to find the index of the last occurrence of each string in the array.
Example:
If this is my array....
let myArray = ["john","john","blake","robert","john","blake"]
I want the last index of each occurrence so...
blake = 5
john = 4
robert = 3
What is the best way to do this in Swift?
Normally I would just make a variable for each item possibility in the array and then increment through the array and count the items but in this case there are thousands of items in the array and they are of unknown values.
Create an array with elements and their indices:
zip(myArray, myArray.indices)
then reduce into a dictionary where keys are array elements and values are indices:
let result = zip(myArray, myArray.indices).reduce(into: [:]) { dict, tuple in
dict[tuple.0] = tuple.1
}
(myArray.enumerated() returns offsets, not indices, but it would have worked here too instead of zip since Array has an Int zero-based indices)
EDIT: Dictionary(_:uniquingKeysWith:) approach (#Jessy's answer) is a cleaner way to do it
New Dev's answer is the way to go. Except, the standard library already has a solution that does that, so use that instead.
Dictionary(
["john", "john", "blake", "robert", "john", "blake"]
.enumerated()
.map { ($0.element, $0.offset) }
) { $1 }
Or if you've already got a collection elsewhereâŠ
Dictionary(zip(collection, collection.indices)) { $1 }
Just for fun, the one-liner, and likely the shortest, solution (brevity over clarity, or was it the other way around? :P)
myArray.enumerated().reduce(into: [:]) { $0[$1.0] = $1.1 }
So I have a plist with a number of items that I would like to access in my project. The plist is an array of items, which are in turn dictionaries with of type string:string (Item1 -> "name" : "somename", "description" : "somedescription")
I would like to access only the name value of my items, and display in an array. I have managed to retreive all the key-value pairs in my plist with the following code:
let path = Bundle.main.path(forResource: "PlistName", ofType: "plist")
let dict = NSArray.init(contentsOf: URL.init(fileURLWithPath: path!)) as! [[String:String]]
by using print(dict) I am able to get everything printed to the console, however like I said I only want the names of the items in an array.
What confuses me the most is the fact that the dict is equal to an NSArray of type [[String:String]]. I do not understand how an array can be of type String:String. This looks like a dictionary to me. I tried changing NSArray to NSDictionary, but that gives me an error saying
"Cast from 'NSDictionary?' to unrelated type '[[String : String]]' always fails"
I'm also not able to tap into either the key or value of dict.
let oneDict = dict[0]
returns one dictionary, and if you really want an array of one dictionary do this:
let array = [oneDict]
You can extract values for a specific key by using the map or compactMap functions, in this case I use compactMap in case one of the dictionaries doesn't contain a name
let arrayOfDictionaries = [["name": "a", "some": "x"],
["name": "b", "some": "y"],
["some": "z"],
["name": "c"]]
let names = arrayOfDictionaries.compactMap {$0["name"]}
i want from tableview to collect MyArray's as value like
Swift:
let total = UILabel()
var MyArray = ["2", "9", "33", "4"]
total.text = ?? // i want result be like this [2+9+33+4] = 48
and if add some value or remove some the result change
i hope i delivered right question and i hope i get the right answer
Iterate through your array, using conditional binding, if the value is invalid, e.g "hello", it won't enter the condition.
var result = 0
for element in MyArray { // MyArray should have the first letter lowercased and have a more meaningful name.
if let number = Int(element) { // or NSNumber, Double, etc...
result = result + number
}
}
total.text = "\(result)" // consider naming it totalLabel
Convert the myArray elements type from String to Double using compactMap. Then add the elements using reduce method. Then convert the result to string to show in label.
var myArray = ["2", "9", "33", "4", "wot?", "đ¶"]
total.text = String(myArray.lazy.compactMap{ Double($0) }.reduce(0, +))//48.0
Two suggestions:
With reduce to sum up the values and ignore non-integer values
total.text = String(myArray.reduce(0, {$0 + (Int($1) ?? 0)}))
With NSExpression if the array contains only string representations of integers. joined converts the array to "2+9+33+4"
let additionExpression = NSExpression(format: myArray.joined(separator: "+"))
total.text = "\(additionExpression.expressionValue(with: nil, context: nil)!)"
There are two steps::
Calculate the total.
Consider:
let array = ["200", "900", "33", "4"]
let total = array
.lazy
.compactMap { Double($0) }
.reduce(0, +)
Note, unlike other suggestions, Iâm refraining from placing this in a single line of code (although one could). The goal of functional programming patterns is to write expressive yet efficient code about which it is easy to reason. Placing all of this onto one line is contrary to that goal, IMHO, though it is arguably a matter of personal preference.
Setting the text of the label.
When setting the text of the label, itâs very tempting to want to just do String(total). But that is not a very user-friendly presentation (e.g. the sum 1,137 will be shown as â1137.0â). Nor is it localized.
The typical solution when displaying a result (whether numbers, dates, time intervals, etc.) in the user interface is to use a âformatterâ. In the case of numeric values, one would typically use a NumberFormatter:
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
label.text = formatter.string(for: total)
For a user in the US, that will show â1,137â, whereas the German user will see â1.137â. So each device sees the number presented in a format consistent with the usersâ localization preferences.
I have an dictionary that I want to iterate trough in a tableview. One way of doing this is to create an array with all the keys and just fetch the key at the given index. But for this array I want the keys to be ordered alphabetically by the values in the dictionary. How do I do this?
static let dict = [
"0P0000KBNA": "LÀnsförsÀkringar Europa IndexnÀra",
"0P0000YVZ3": "LÀnsförsÀkringar Global IndexnÀra",
"0P0000J1JM": "LÀnsförsÀkringar Sverige IndexnÀra",
"0P00013668": "LÀnsförsÀkringar TillvÀxtmarknad IndexnÀra A",
"0P0000K9E7": "LÀnsförsÀkringar USA IndexnÀra",
"0P00005U1J": "Avanza Zero"
]
static let sortedKeys = Array(dict.keys) // How?
You just need to sort your dictionary by value and map the key
let sortedKeys = dict.sorted{$0.value < $1.value}.map{$0.key} // ["0P00005U1J", "0P0000KBNA", "0P0000YVZ3", "0P0000J1JM", "0P00013668", "0P0000K9E7"]
As a minor variation of #LeoDabus answer, you could access the keys property of your dictionary and sort this array according to the corresponding value for each key
let sortedKeys = dict.keys.sorted { dict[$0]! < dict[$1]! }
print(sortedKeys)
/* ["0P00005U1J",
"0P0000KBNA",
"0P0000YVZ3",
"0P0000J1JM",
"0P00013668",
"0P0000K9E7"] */
Note also that the forced unwrapping operator ! is generally to be avoided, but in this particular case, we know that both shorthand arguments $0 and $1 in the predicate closure supplied to sorted(...) are guaranteed to be valid keys in the dictionary (since your dictionary is immutable: so no asynch risks here).
First, make a new array of strings called keysArray.
Second, loop over your array of dictionaries and add all the keys to the newly created array.
Now keysArray should be an array of the keys.
Third, sort sortedKeysArray as follow
var sortedArray = sortedKeysArray.sorted { $0.localizedCaseInsensitiveCompare($1) == NSComparisonResult.OrderedAscending}
Now we have an array of the sorted Keys.
After this if you need to have an array of the dictionaries, create a new array called sortedDictArray. Then loop over sortedKeysArray we made previously and get the dictionary by key and add it to sortedDictArray. Viola!
Hope this helps you!
Ordered Dictionary
I've used the open source OrderedDictionary created by Lukas Kubanek to solve problems like this.
For the usage of this library you can refer to the example playground.
This question already has answers here:
Get an array of property values from an object array
(2 answers)
Closed 6 years ago.
I get an element from a collection with this code:
modelCollec[indexPath].model
I want to get all models in an array. Is there a function or shall I write a loop?
There is only one row so indexPath is always [0, index].
Use flatMap for that.
let modelArray = modelCollec.flatMap { $0.model }
modelArray type is [model].
For eg:
struct Person {
var name: String
}
Now if you have array of person and you want array of name from it you can get it using flatMap like this way.
let persons = [Person]()
let nameArray = persons.flatMap { $0.name } //nameArray type is [String]
Note: You can also use map instead of flatMap but it will give you optional objects if your model property is optional so it may contains nil where as flatMap ignore the nil object.
If you always want to access the 1st element of the collection then it is a better idea to hardcode the 0 index rather than using loop, however to it is always better to put a check for nil.