I'm trying to make an app that will select an index at random, something like 0-1000 and then print the key, value, and link of the selected number to three seperate labels on the iPhone simulator.
So from my example, I want to randomly select "0" or "1" and if for instance "1" was chosen; then the key, value, and link information would each be printed to three separate labels on the simulator. The following is what I've been working on in playgrounds. Is there a better way to go about this?
var spDictionary: [String: [String:String]] = [
"0": ["key": "AMZN", "value": "AMAZON", "link": "yahoo"],
"1": ["key": "AAPL", "value": "APPLE", "link": "yahoo2"],
]
And for the random aspect I think it would be something like this but I'm not sure? Sorry for the newbie question.
let randomIndex: Int = Int(arc4random_uniform(UInt32(spDictionary.count)))`
Even for small data structures it's worth it to create a custom class or struct
struct Data {
let key : String
let value : String
let link : String
}
Create an object
let data = Data(key: "AMZN", value: "AMAZON", link: "yahoo")
Get a property
let link = data.link
and you can declare your dictionary
var spDictionary : [String: Data] = ...
Related
I m mapping data that come from service with using dictionary [String: String]. I collect them dictionary array. For example, if their parent ids are the same, I want to add their values by array value.
["ParentId": "1","Value": "["Giyim","Aksesuar","Ayakkabı"]"]
It is also the reason I don't know parent id sometimes on the left sometimes on the right in photo
Here is my code and its output.
struct Categories {
let parentId: String
let values: [String]
}
for result in results {
if result?.parentCategoryId != "" {
for docId in self.docIds {
if result?.parentCategoryId == docId {
//print(result?.name)
var values = [String]()
values.append(result?.name ?? "")
self.newCat.append(Categories(parentId: docId, values: values))
}
}
}
}
Problem
As far as I understand from the description you want to map some service data structure to a dictionary where key is parentId and value is an array of some items referred to parentId.
I believe your problem comes from a misunderstanding of the concept of dictionary as a data structure.
[String: String] is dictionary where keys and their associated values are of String type. For example:
["firstKey": "firsthValue", "secondKey": "secondValue", ...]
That means you cannot store associated values of String and Array types in the same dictionary, as you already told the compiler you would like to store only strings.
It is also the reason I don't know parent id sometimes on the left sometimes on the right in photo
This is because key-value pairs are stored in the dictionary without order. This is how dictionaries work :) I'd strongly recommend reading some short official materials to get used to them.
New Swift 5.4 version has a new OrderedDictionary data structure, where keys are ordered, but there is absolutely 100500% no reason to use it for your problem*
Possible solutions
In your case i would suggest either use some struct:
struct SomeData {
let parentID: Int
var values: [String]
}
var storage: [SomeData] // alternative to emptyDic
// Filling storage with data from service
for result in inputData {
// search for SomeData with required id, add value
// OR create SomeData if there is no such id in array yet
}
OR [personally this appeals to me more]
Store data in [String: [String]] dictionary, where the key is parentID and the associated value is an array of values.
The algorithm of filling this dictionary is pretty the same:
You add new key-value pair for every new parentID
You append new values for parentIDs that are already in the dictionary.
Using the struct approach, you could do something like this (you'll need to adapt it to your code, but that should be straightforward):
struct Categories {
let parentId: String
var values: [String] //notice this needs to be a var, not a let
}
func addItem(categories : inout [Categories], docId: String, name: String) {
if let index = categories.firstIndex(where: { $0.parentId == docId }) {
categories[index].values.append(name)
} else {
categories.append(Categories(parentId: docId, values: [name]))
}
}
func addValues() {
var categories = [Categories]()
addItem(categories: &categories, docId: "4", name: "Test1")
addItem(categories: &categories, docId: "1", name: "Test")
addItem(categories: &categories, docId: "4", name: "Test2")
addItem(categories: &categories, docId: "4", name: "Test3")
print(categories)
//in your code, it'll look more like:
// addItem(categories: &self.newCat, docId: docId, name: result?.name ?? "")
}
Which yields this:
[
StackOverflowPlayground.Categories(parentId: "4", values: ["Test1", "Test2", "Test3"]),
StackOverflowPlayground.Categories(parentId: "1", values: ["Test"])
]
I still wonder whether you maybe just want a Dictionary that is keyed by the parentId, but not knowing your use case, it's hard to say.
I'm using SwiftyJSON to parse a nested JSON. The JSON is used to populate a form where the user is shown the "keys" from the JSON to select from and then the corresponding values to the selection are used to calculate a score.
I've tried to parse the JSON and the parsing works well to get the rest of the data (e.g. the question) but when I try to parse the portion of the JSON where the scores (key: values) are, I get null.
{
"Question": "Pick a Number from the given values",
"Answer_Choices": {
"10": "6",
"9": "6",
"8": "3",
"7": "3",
"6": "1"
}
}
In the above code I want to display the left numbers to the user where they pick the 'keys' and correspondingly I will assign the values the values to contribute to the user's score, e.g. if the user selects 8, I'll assign them 3. I'm not sure how I can cast the key as well as values dynamically. They always fill up as null.
Question is parsed as:
var question = JSON["Question"].string
var answerChoices = JSON["Answer_Choices"].dictionaryObject // I know this is probably not correct.
You are pretty close. Here is how you can parse to get separate arrays for answers and points
guard let dict = json["Answer_Choices"].dictionaryObject as? [String:String] else {
return
}
let answerArray = Array(dict.keys)
let pointsArray = Array(dict.values)
I have a dictionary like below,
var dataSource: [String: String] = ["FirstName": "Austin",
"ListName": "Michael",
"Address": "Street Address",
"City": "Chennai"]
I want to populate these values in a UITableView, so I tried to get all the keys from Dictionary to an Array like below,
let dataArray = Array(dataSource.keys)
I got the output as [String] like,
["LastName", "FirstName", "City", "Address"]
The problem is, the order of the keys has changed, I want the array in the same order as dictionary has.
Can you anyone help?
Use plain dictionary as tableview datasource is bad idea.
However Dictionary can not be sorted. So it doesn't matter in what order you add your keys-values to the dictionary.
If you need sorted then use array of dictionary instead.
You should use models instead of plain dictionary that is easy to maintain :]
like
struct User {
var firstName:String?
var lastName:String?
var address:String?
var city:String?
}
Do you guys can bring some light on the use of dictionaries with UserDefaults ?
What I want to get is to pass a certain dictionary from a view controller to another one using UserDefaults.
var dict = [String : AnyObject?]()
dict = ["Name": "Henri", "Group": "A", "Category": "4"]
UserDefaults.standard.set.(dict, forKey: "MyDict")
Then I try to retrieve the data
let retrieveDict = UserDefaults.standard.dictionary(forKey:"MyDict")
I got a nice nil answer in the console. When I try with int or float types it is fine... Is there anything I am missing to make this dictionary ?
First of all, your code won't compile.
Second, a dictionary with type [String, AnyObject?] make no sense because you'll be not able to set nil in UserDefaults. You should use empty String maybe for that purpose.
The working code could look like that :
var dict = [String : Any]() // or maybe [String : String] if you sure about value type
dict = ["Name": "Henri", "Group": "A", "Category": "4"]
UserDefaults.standard.set(dict, forKey: "MyDict")
let retrieveDict = UserDefaults.standard.dictionary(forKey:"MyDict")
Hope it helps you :)
I have a Dictionary of number String that looks like this:
let comph : [String : [String : String]] = [
"1":["title" : "first title"],
"2":["title" : "second title"],
"10": ["title" : "last title"]
]
Then when I sort my Dictionary using comph.sort { $0.0 < $1.0 } I get this:
let sortedComph = comph.sort { $0.0 < $1.0 }
print(sortedComph) //["1":["title" : "first title"],"10": ["title" : "last title"],"2":["title" : "second title"]]
How can I sort the Dictionary so that it returns the keys in numerical order?
eg: ["1":["title" : "first title"],"2":["title" : "second title"],"10": ["title" : "last title"]]
Thanks'
Dictionaries in Swift, by definition, are unsorted collections. You'll need to use some other type if you want to maintain order.
But, it looks like this guy wrote an OrderedDictionary in Swift, if you're interested:
Learning Swift: Ordered Dictionaries
Or, a quick n' dirty solution would be to extract the keys to an array, sort those, then iterate over the array and do a dictionary lookup using the keys.
The sortedComph constant in your example is no longer a dictionary, but an array of (key, value) tuples. The problem you're running into is that when sorting strings, the comparison is done without treating the strings as numeric values. That's what you need to fix.
One way to handle this is by creating Int? instances from your strings in your comparison function:
let sortedComph = comph.sort { Int($0.0) < Int($1.0) }
// [("1", ["title": "first title"]), ("2", ["title": "second title"]), ("10", ["title": "last title"])]
That way the resulting array will be sorted by the integer value of what's in the string keys. Any non-Integer keys will be grouped at the beginning of the list, since that's how nil sorts.
The more robust way is probably to use the NSString.compare(:options:) method:
let sortedComph = comph.sort {
($0.0 as NSString).compare($1.0, options: .NumericSearch) == .OrderedAscending
}
// [("1", ["title": "first title"]), ("2", ["title": "second title"]), ("10", ["title": "last title"])]
if you want you could have an array of structure representing your data
struct Model
{
var key:String!
var title:String!
// etc...
}
Then declare the array of that structure:
var arrayOfStructure = [Model]()
Then you sorted it