Removing a value at a specified index of a dictionary swift - ios

I am writing a function that deletes a search from an apps NSUserDefaults. The method removes the deleted search from the searches Dictionary. I am confused about the syntax of this function. I don't understand how we access the value of the searches Dictionary with the searches[tags[index]]. To access the value at that index of the searches Dictionary wouldn't we just say searches[index] ?
private var searches: Dictionary <String, String> = [:] // stores tag-query pairs
private var tags: Array<String> = [] // stores tags in user-specified order
// returns the query String for the taga at a given index
func queryForTagAtIndex(index: Int) -> String? {
return searches[tags[index]]
}

Since your dictionary is of the type [String:String] to access or add a value to it, the key should be of type String and not Int. index is of Type Int. So it will give an error if we do return searches[index]. And since tags is of type String, we can use that as the key for the searches.
Here are some links that will help you : https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/CollectionTypes.html
https://developer.apple.com/library/ios/documentation/General/Reference/SwiftStandardLibraryReference/Dictionary.html
And I would edit the code for readability purposes to this :
private var searches:[String:String]=[String:String]() // stores tag-query pairs
private var tags:[String] = [String]() // stores tags in user-specified order
// returns the query String for the taga at a given index
func queryForTagAtIndex(index: Int) -> String? {
return searches[tags[index]]
}

Related

Sorting Array returns a Dictionary

I have the following object:
private var datasource: [Int: [MyCustomModel]] = [:]
At a later stage, I need to sort the datasource by the key property (ascending).
I do it as follows:
let sorted = datasource.sorted(by: {$0.key < $1.key})
This does sort the content by the key (Int) value perfectly, though I cannot set the datasource to the sorted property.
Xcode presents the following error
Cannot assign value of type '[Dictionary<Int, [MyCustomModel]>.Element]' (aka 'Array<(key: Int, value: Array)>') to type '[Int : [MyCustomModel]]'
I get that the returned type, after sorting is a Dictionary and not an Array.
How can I overcome this issue?
Thanks.
I didn't get any solution for the same to sort the dictionary, but you can do something like below.
Its works for me.
make structure of key and value.
struct STRUCT_TEMP
{
var key : Int
var value : [MyCustomModel]
}
create structure variable.
var structTemp : [STRUCT_TEMP] = []
convert your dictionary in structure like below:
self.structTemp = datasource.map({ STRUCT_TEMP(key: $0.key, value: $0.value) })
now you can do anything with the structTemp array. Like sorting, filter and you can also use this array everywhere you want instead of dictionary.
let datasource: [Int: [MyCustomModel]] = [:]
Dictionaries cannot be sorted!. If you use sorted(by: { $0.key < $1.key}) to sort the datasource, the result is an array, not a dictionary.
datasource.sorted(by: { $0.key < $1.key})
Swift 5.5
You can use OrderedDictionary. It keeps insertion order.
https://www.advancedswift.com/ordereddictionary/

Realm Results array sorted by primary key is not coming out actually sorted

I've got a Realm db containing objects, the primary key is a string containing numbers i.e.
#objc public class Caller : Object
{
#objc dynamic var number = ""
...
override public static func primaryKey() -> String? {
return "number"
}
If I try to retrieve the objects sorted by the key they are not coming out in order i.e.
let results = realm.objects(Caller.self).sorted(byKeyPath: "number")
If the db contains 3 objects with values for number of 12037366517, 12037600287, 67725082. Then if I iterate through results and log "number" the results are:
12037366517
12037600287
67725082
Why are they not coming out in sorted order?
This is expected behaviour if number is a string. When sorting strings in ascending order, it is sorted in lexicographical order. So the character "3" comes after "2", which comes after "1" etc. Your results are sorted correctly, just not as you expected it.
You can fix this by sorting on an actual numeric value. The best way would be to actually store the numbers as integers instead of strings. If that is not possible, you will have to manually sort, but I think that will be less performant.
let results = realm.objects(Caller.self).sorted { (a, b) -> Bool in
if let aInt = Int(a), let bInt = Int(b) {
return aInt < bInt
}
return false
}

iOS Swift 3 - Argument labels '(of:)' do not match any available overloads Error

I'm getting the error message Argument labels '(of:)' do not match any available overloads. Below is the code I'm using.
let prefs = UserDefaults.standard
var id: String!
if var array = prefs.string(forKey: "myArray"){
if let index = array.index(of: id) {
array.remove(at: index)
prefs.setValue(array, forKey: "myArray")
}
}
I've seen a lot of answers on Stack Overflow with very similar code to that. So I'm not quite sure why this wouldn't be working.
Basically I'm just trying to remove the element in the array that = id then set that new array to the user defaults.
Update
Just updated the code above to show how array is getting defined. id is a string that is defined in a separate section.
By accessing prefs.string(forKey: "myArray"), you are getting a String, not an array of strings. You should use this:
if var prefs.array(forKey: "myArray") as? [String] { }
or
if var prefs.value(forKey: "myArray") as? [String] { }
Make sure to not forget putting as! [String], because the first method returns [Any], an which can contain objects of any type, not specifically String. Then your error should be solved, because index(of: ) can only be used on Arrays of specified types.
Hope it helps!
Just make an alt + Click on an "array" variable to make sure it is of type Array ([String]), not a String. To apply .index(of:) method it must be an array.
Like this:
String does not have a method .index(of:). That's what the error is pointing at. And sure make a cast to [String]? if it fits.

Proper way to get swift dictionary item index

I have dictionary in my app written in Swift
var cities: [String: String] = ["":"not specified", "ny":"New York", "la":"Los Angeles", "sf":"San Francisco"]
I use this dictionary to build pickerView. When user selects one of this items - city code is saving to device memory.
When user opens app next time I want pickerView to show saved city. How should i do it?
You can find the index of a key in a dictionary with higher-order functions:
let desiredKey = "ny"
let pos = x.enumerate().filter { (pair: (index: Int, element: (String, String))) -> Bool in
return pair.element.0 == desiredKey
}.map { (pair: (index: Int, element: (String, String))) -> Int in
return pair.index
}
pos is an Optional(Int) containing the position of "ny" in the current iteration order of the dictionary.
Store the value of the key somewhere (say, in user defaults), then retrieve it, get the index of the key-value pair using the code above, and pass to selectedRowInComponent: of your picker view.
Note: The problem with using a dictionary alone as a backing for your picker is that the order is not specified explicitly. Adding or removing keys may change the order of existing keys. In addition, existing keys may not end up in places that you want them to be - for example, your "" - "not specified" pair may end up in the middle of the picker.
To fix this problem, keep a separate array of city keys in the proper order that you wish to follow. Use this array to decide the picker row in which a city is to be displayed, and look up the actual city using the dictionary.
You can use NSUserDefaults to insure the persistency of your cityCode.
Copy an paste this sample in a playground.
var cities: [String: String] = ["":"not specified", "ny":"New York", "la":"Los Angeles", "sf":"San Francisco"]
let cityCodeIndexKey="cityCodeIndexKey"
/**
Selects and saves the cityCode
- parameter cityCode: a cityCode String
- returns: true if the code exists.
*/
func selectCity(cityCode:String)->Bool{
if let _ = cities.indexForKey(cityCode){
NSUserDefaults.standardUserDefaults().setObject(cityCode, forKey:cityCodeIndexKey)
NSUserDefaults.standardUserDefaults().synchronize()
return true
}else{
return false
}
}
selectCity("ny") // Returns true
selectCity("pr") // Returns false
NSUserDefaults.standardUserDefaults().valueForKey(cityCodeIndexKey) // returns "ny"
Get key,
var cityLongName <- user selected one
var key = dict.first((key,value) In{
If (value == cityLongName ){
return true
}else{
return false
}
}).key!
Get values ,
var value = dict[“city sort name”]

Swift: Declaring empty tuples

What's the correct way to declare an empty tuple?
For Arrays: var myArr : [String] = []
For tuples: var myTuple: (key: String, val: Int) = () ?
Is there a correct way to achieve this?
There's no such thing as an "unfilled" tuple value. In other words you don't create an empty tuple and then add values to it later. It's important to remember that tuples aren't collections like Array or Dictionary. Tuples are structured types. For example, you can't iterate through a tuple with a for loop. In your example, myTuple is a single value that happens to contain a String and an Int.
A tuple is like an on-demand unnamed structure, such as the following struct but if it were possible for it to be unnamed:
struct MyStruct {
let key: String
let val: Int
}
If you want to model a missing tuple value, you should make the type of the entire tuple optional. For example:
var myTuple: (key: String, val: Int)? = nil

Resources