I have a stored NSMutableDictionary in NSUSerDefaluts and i have retrieve that successfully.
if var tempFeed: NSDictionary = NSUserDefaults.standardUserDefaults().dictionaryForKey("selectedFeeds") {
println("selected Feed: \(tempFeed)")
savedDictionary = tempFeed.mutableCopy() as NSMutableDictionary
The Question is How can i convert that MutableDictionary into an array/MuatableArray and iterate it so i can get the values of it.Here is the Dictionary. i want to get the values for all URL in that.
{
4 = {
URL = "myurl1";
};
5 = {
URL = "myurl3";
};
6 = {
URL = "myurl3";
};
}
I have tried number of options with failure.
Thank you.
If you want to add all the urls into an array, iterate over it and add append all values to some array.
for (_,urlDict) in savedDictionary {
for(_,url) in urlDict {
urlArr.append(url) // create empty urlArr before
}
}
urlArr now contains all the urls (not ordered)
You can use .values.array on your dictionary to get the values unordered.
as an array
Then, you can just add your NSArray to your NSMutableArray.
var mutableArray:NSMutableArray = NSMutableArray(array: savedDictionary .values.array)
If all you want to do is iterate over it, you don’t have to convert it to an array. You can do that directly:
for (key,value) in savedDictionary {
println("\(key) = \(value)")
}
(if you’re not interested in the key at all, you can replace that variable name with _ to ignore it).
Alternatively, instead of making tempFeed of type NSDictionary, just leave it as the type dictionaryForKey returns, which is a Swift dictionary. This has a .values property, which is a lazy sequence of all the values in the dictionary. You can convert that to an array (so tempFeed.values.array) or perform operations on it directly (use it in for…in, map it such as tempFeeds.values.map { NSURL(string: toString($0)) } etc.)
Related
I'm trying to show a tableview similar to contacts with my list of users.
I declare a global variable of friends that will store the first character of a name and a list of users whose first name start with that
var friends = [Character: [User]]()
In my fetch method, I do this
for friend in newFriends {
let letter = friend.firstName?[(friend.firstName?.startIndex)!]
print(letter)
self.friends[letter!]?.append(friend)
}
After this, I should have my friends array with the first letter of the name and the users that fall in it; however, my friends dictionary is empty.
How do I fix this?
Edit: I'm following this tutorial and he doesnt exactly the same.. Swift: How to make alphabetically section headers in table view with a mutable data source
Rather than using Character as the key, use String. You need to be sure to init the [User] array for every new First Initial key you insert into groupedNames. I keep an array of groupedLetters to make it easier to get a section count
var groupedNames = [String: [User]]()
var groupedLetters = Array<String>()
func filterNames() {
groupedNames.removeAll()
groupedLetters.removeAll()
for friend in newFriends {
let index = friend.firstName.index(friend.firstName.startIndex, offsetBy: 0)
let firstLetter = String(friend.firstName[index]).uppercased()
if groupedNames[firstLetter] != nil {
//array already exists, just append
groupedNames[firstLetter]?.append(friend)
} else {
//no array for that letter key - init array and store the letter in the groupedLetters array
groupedNames[firstLetter] = [friend]
groupedLetters.append(firstLetter)
}
}
}
Creating a Dictionary structure with Characters as keys & values as Array of User will be more succinct.
The error occurs because you are declaring an empty dictionary, that means you have to add a key / empty array pair if there is no entry for that character.
Consider also to consolidate the question / exclamation marks
class User {
let firstName : String
init(firstName : String) {
self.firstName = firstName
}
}
var friends = [Character: [User]]()
let newFriends = [User(firstName:"foo"), User(firstName:"bar"), User(firstName:"baz")]
for friend in newFriends {
let letter = friend.firstName[friend.firstName.startIndex]
if friends[letter] == nil {
friends[letter] = [User]()
}
friends[letter]!.append(friend)
}
I've looked through the methods here but I can't quite find what I'm looking for. I'm new-ish to Swift. I would like to extract a subset from a Dictionary based on a Set of key values, preferably without a loop.
For example, if my key Set is of type Set<String> and I have a Dictionary of type Dictionary<String, CustomObject>, I would like to create a new Dictionary of type Dictionary<String, CustomObject> that contains only the key-value pairs associated with the keys in the Set of Strings.
I can see that I could do this with for loop, by initializing a new Dictionary<String, CustomObj>(), checking if the original Dictionary contains a value at each String in the set, and adding key-value pairs to the new Dictionary. I am wondering if there is a more efficient/elegant way to do this however.
I'd be open to finding the subset with an Array of Strings instead of a Set if there is a better way to do it with an Array of keys.
Many thanks!
Swift 5 - You can do this very simply:
let subsetDict = originalDict.filter({ mySet.contains($0.key)})
The result is a new dictionary with the same type as the original but which only contains the key-value pairs corresponding to the keys in mySet.
Your assumption is correct, there is a more concise/swift-ish way to accomplish what you need.
For example you can do it via reduce, a functional programming concept available in Swift:
let subDict = originalDict.reduce([String: CustomObject]()) {
guard mySet.contains($1.key) else { return $0 }
var d = $0
d[$1.key] = $1.value
return d
}
Or, in two steps, first filtering the valid elements, and then constructing back the dictionary with the filtered elements:
let filteredDict = originalDict.filter { mySet.contains($0.key) }
.reduce([CustomObject]()){ var d = $0; d[$1.key]=$1.value; return d }
forEach can also be used to construct the filtered dictionary:
var filteredDict = [CustomObject]()
mySet.forEach { filteredDict[$0] = originalDict[$0] }
, however the result would be good it it would be immutable:
let filteredDict: [String:CustomObject] = {
var result = [String:CustomObject]()
mySet.forEach { filteredDict2[$0] = originalDict[$0] }
return result
}()
Dummy type:
struct CustomObject {
let foo: Int
init(_ foo: Int) { self.foo = foo }
}
In case you'd like to mutate the original dictionary (instead of creating a new one) in an "intersect" manner, based on a given set of keys:
let keySet = Set(["foo", "baz"])
var dict = ["foo": CustomObject(1), "bar": CustomObject(2),
"baz": CustomObject(3), "bax": CustomObject(4)]
Set(dict.keys).subtracting(keySet).forEach { dict.removeValue(forKey: $0) }
print(dict) // ["foo": CustomObject(foo: 1), "baz": CustomObject(foo: 3)]
I'm saving lists in a dictionary. These lists need to be updated. But when searching for an item, I need [] operator. When I save the result to a variable, a copy is used. This can not be used, to change the list itself:
item = dicMyList[key]
if item != nil {
// add it to existing list
dicMyList[key]!.list.append(filename)
// item?.list.append(filename)
}
I know, that I need the uncommented code above, but this accesses and searches again in dictionary. How can I save the result, without searching again? (like the commented line)
I want to speed up the code.
In case you needn't verify whether the inner list was actually existing or not prior to adding element fileName, you could use a more compact solution making use of the nil coalescing operator.
// example setup
var dicMyList = [1: ["foo.sig", "bar.cc"]] // [Int: [String]] dict
var key = 1
var fileName = "baz.h"
// "append" (copy-in/copy-out) 'fileName' to inner array associated
// with 'key'; constructing a new key-value pair in case none exist
dicMyList[key] = (dicMyList[key] ?? []) + [fileName]
print(dicMyList) // [1: ["foo.sig", "bar.cc", "baz.h"]]
// same method used for non-existant key
key = 2
fileName = "bax.swift"
dicMyList[key] = (dicMyList[key] ?? []) + [fileName]
print(dicMyList) // [2: ["bax.swift"], 1: ["foo.sig", "bar.cc", "baz.h"]]
Dictionaries and arrays are value types. So if you change an entry you'll need to save it back into the dictionary.
if var list = dicMyList[key] {
list.append(filename)
dicMyList[key] = list
} else {
dicMyList[key] = [filename]
}
It's a little bit late, but you can do something like this:
extension Optional where Wrapped == Array<String> {
mutating func append(_ element: String) {
if self == nil {
self = [element]
}
else {
self!.append(element)
}
}
}
var dictionary = [String: [String]]()
dictionary["Hola"].append("Chau")
You can try this in the Playground and then adapt to your needs.
I have been attempting for a while now to add in an extra dictionary value into a NSMutableArray containing NSDictionaries at each index.
I have tried several approaches detailed below.
func findDistanceAndSortArray(offers : NSMutableArray){
for (index, offer) in enumerate(offers) {
var json = JSON(offer)
if let location = json["company"]["address"]["location"].dictionary {
//Not important Location code is here <-----
var distance = self.calculateDistance(newLat, longitude: newLngg)
var newDistance = ["totalDistance" : distance]
// I have tried these ....
// offers.insertObject(newDistance, atIndex: index)
// offer[newDistance]
// json["totalDistance"] = "" <-- this inserts the dictionary but I cannot add a string into ANYOBJECT
}
println("MORE inside \(json)")
println("MORE inside \(offers)")
}
}
The closest I got was using json["totalDistance"] = "" which inserted the value alongside its key but when I tried to add in the string it produced a error saying can't add string to value type JSON (As I am using SwiftyJson for parsing)
Can't seem to figure this one out but I'm sure its simple.
Thirst: you must not change an array while iterating thru the same array. Because you tried to:
// I have tried these ....
// offers.insertObject(newDistance, atIndex: index)
And the solution should be:
json["totalDistance"].string = distance
Please try, I currently have no compiler to test it.
I have this block of code
//start of the loop
if let objects = objects as? [PFObject] {
for object in objects {
//saving the object
self.likerNames.setObject(object["fromUserName"]!, forKey: saveStatusId!)
}
}
likerNames is an NSMutableArray declared earlier, saveStatusId is a string I also declared and saved earlier (It's just an objectId as a String), and object["fromUserName"] is an object returned from my query (not shown above).
Everything is working fine as it is but my query sometimes returns more than one object["fromUserName"] to the same key which is saveStatusId. When this happens the value I have for that saveStatusId is replaced when I actually want it to be added to the key.
So want it to kind of look like this
("jKd98jDF" : {"Joe", "John"})
("ksd6fsFs" : {"Sarah"})
("payqw324" : {"Chris", "Sarah", "John"})
I know you can use Arrays but I'm not sure how I would go about that to get it to work in my current situation.
So my question would be how to I get my key (saveStatusId) to store more than one value of object["fromUserName"]?
Something like this could work
let key = saveStatusId!
let oldValue = self.likerNames.objectForKey( key ) as? [String]
let newValue = (oldValue ?? []) + [ object["fromUserName" ] ]
self.likerNames.setObject( newValue, forKey: key )
If likerNames has an array in slot[saveStatusId], append the new value, otherwise create an array and put that in the right slot