Swift 2.0, xcode 7.1
I am trying to retrieve some data from Parse database, filter it to remove duplicate and store in a dictionary. Each row of parse has orders placed by customer (JSON shown below) and I want to retrieve this in UITableView to show the order placed. If the customer has placed multiple orders recently, I want to filter that and show all of his orders in one section of table view under his customer ID.
Filtering is working, but for some reason my loop is not giving me accurate results.
Parse Row 1:
[{"Customer":"9sKSDTG7GY","Product":"Burger","Quantity":"2"}]
Parse Row 2:
[{"Customer":"nyRHskbTwG","Product":"Sizzler","Quantity":"2"},{"Customer":"nyRHskbTwG","Product":"Biryani","Quantity":"2"}]
Retrieved this data and stored in self.custome, self.fQuantity and self.fName variable.
The loop I am using is as below:
let cD = self.customer
print("Customer data before filtering Unique value: \(self.customer)")
self.uniqueValues = self.uniq(cD) //Calling a function to get unique values in customer data
print("Customer data after filtering Unique value: \(self.uniqueValues)")
var newArray = [[String]]()
for var count = 0; count < self.customer.count; count++ {
for sID in self.uniqueValues {
if sID.containsString(self.customer[count]){
let dicValue = [String(self.fQuantity[count]), String(self.fName[count])]
newArray.append(dicValue)
self.dicArray.updateValue(newArray, forKey: sID)
} else {
// Do nothing...
}
}
}
print("Dictionary Values: \(Array(self.dicArray.values))")
print("Dictionary Keys: \(Array(self.dicArray.keys))")
Printed output is as below:
Customer data before filtering Unique value: ["9sKSDTG7GY",
"nyRHskbTwG", "nyRHskbTwG"]
Customer data after filtering Unique value: ["9sKSDTG7GY",
"nyRHskbTwG"]
Dictionary Values: [[["2", "Burger"], ["2", "Sizzler"],
["2", "Biryani"]], [["2", "Burger"]]]
Dictionary Keys: ["nyRHskbTwG", "9sKSDTG7GY"]
Can someone figure out what I am doing wrong?
As #David suggested, you have to swap outer and inner loop. But I also had to delete all values contained in newArray if there was nothing found in the if loop. So this is how I made it work.
let cD = self.customer
print("Customer data before filtering Unique value: \(self.customer)")
self.uniqueValues = self.uniq(cD) //Calling a function to get unique values in customer data
print("Customer data after filtering Unique value: \(self.uniqueValues)")
var newArray = [[String]]()
for sID in self.uniqueValues {
for var count = 0; count < self.customer.count; count++ {
if sID.containsString(self.customer[count]){
let dicValue = [String(self.fQuantity[count]), String(self.fName[count])]
newArray.append(dicValue)
self.dicArray.updateValue(newArray, forKey: sID)
} else {
newArray.removeAll() // ****** Adding this works for me
}
}
}
print("Dictionary Values: \(Array(self.dicArray.values))")
print("Dictionary Keys: \(Array(self.dicArray.keys))")
You filtered the data, but are looping through the un-filtered list of customers.
for var count = 0; count < self.customer.count; count++ {
Related
{
"userID": "MyID123"
"voteInfo": {
"docId1": 1
"docId2": 1
"docId3": 2
....
}
}
I would like to record which number the user voted for each two-point questionnaire. At first, only the user ID exists in the 'users' document, and I want to add data whenever I update it.
My code that is not working is as follows.
let userID = "MyID123"
let docID = "Ffeji341Fje3"
db.collection("users").document(userID).updateData([
"voteInfo": [
docID: 1
]
])
If you want to store the vote count for a number of keys:
Don't store the counts as an array, but store them in a map field.
Use the atomic increment operator to increase the vote count.
let key = "voteInfo."+docId
let update = [String:Any]
update[key] = FieldValue.increment(Int64(1))
db.collection("users").document(userID).updateData(update)
You can do this pretty easily through dot notation.
Given this Firestore structure
user_votes
uid_0
voteInfo //a map
docId1: 1
docId2: 1
docId3: 2
here's a function to append docId4: 1 to the existing docs
func addDoc() {
let collection = db.collection("user_votes").document("uid_0")
let newData = [
"voteInfo.docId4": 1
]
doc.updateData(newData, completion: { error in
if let err = error {
print(err.localizedDescription)
return
}
print("success")
})
}
I am trying to filter my dictionary according to user input in UISearchController. I have following model and array of objects.
struct People {
var name: String
var id: Int
}
let first = People(name: "Atalay", id: 1)
let second = People(name: "Ahmet", id: 2)
let third = People(name: "Mehmet", id: 3)
let fourth = People(name: "Yusuf", id: 4)
let peoples: [People] = [first, second, third, fourth, fifth]
I put them into a dictionary to create section indexed table view with following code.
var dict: [String: [People]] = Dictionary(grouping: peoples, by: { (people) -> String in
return String(people.name.prefix(1))
})
Above code gives me a dictionary with first letter of People names. Now, I would like to filter my array according to user input. However, I tried following code for filtering but it is not working as I expected.
let filteredDict = (dict.filter { $0.1.contains { $0.name.lowercased().contains("ata") } })
It returns all "A" letter section indexes like ["A": People(name: "Atalay", id: 1), People(name: "Ahmet", id: 2)]
How can I achieve filter also my array inside dictionary?
If I'm not mistaken, you want your final dictionary to have all the keys and only the filtered array of items as the values. If that is right, reduce is the tool for that:
let filtered = dict.reduce(into: [String: [People]]()) {
$0[$1.key] = $1.value.filter { $0.name.lowercased().contains("ata") }
}
I decided it was simplest to get this right by using an old fashioned for loop and filter each group separately
var filtered = [String: [People]]()
for (k, v) in dict {
let result = v.filter {$0.name.lowercased().contains("ata")}
if result.count > 0 {
filtered[k] = result
}
}
Note that if you want to keep all the groups in the result dictionary just skip the if result.count > 0 condition
How can I achieve filter also my array inside dictionary?
You should have an array first, you can use flatMap to group all the values in your filteredDict
let array = filteredDict.flatMap { $0.value }
Then you just filter the array as usually
let filteredArray = array.filter { $0.name.lowercased().contains("ata") }
I had a problem with firebase , i have 5 document IDs . I need to query those 5 documents , convert them in to object.
for oneID in allIDs {
self.db.collection("storecollection").document(oneID).getDocument {(snap,err) in
let oneobject = convertToObject(snap)
self.tempHolder.append(oneobject)
var newarray = [MyObjectClass]()
if allIDs.last == oneID {
// perform copy
for x in 0...(self.tempHolder.count -1){
newarray.append(self.tempHolder[x])
}
self.tempHolder.removeAll()
completion(newarray)
}
}
Something wrong with code above , the size of self.tempHolder always count = 1. (Only the last id fetched object exist) i have no idea how to make it right.
Whats the right way to fetch multiple document (with specifiedID) ???
There's a bit of extraneous code in the question so it's not exactly clear but it seems you want to iterate over an array of document keys, read each associated document and add properties to an array (or in your case create an object based on those properties and add it)
Here's a simple example reading in a series of posts, and appending the post text from each post in an array.
The structure is
posts //a collection
post_0
post_text: "A post"
post_1
post_text: "Another post"
post_2
post_text: "Cool post"
and the code to read in post_0 and post_2 and append the post text to an array
var postTextArray = [String]()
func readMultiplePosts() {
let postKeyArray = ["post_0", "post_2"]
for postKey in postKeyArray {
let docRef = self.db.collection("posts").document(postKey)
docRef.addSnapshotListener { documentSnapshot, error in
guard let document = documentSnapshot else {
print("err fetchibng document")
return
}
guard let data = document.data() else {
print("doc was empty")
return
}
print("doc data: \(data)")
let post = document.get("post_text") as! String
self.postMsgArray.append(post)
}
}
}
then sometime later we want to print the post texts
for p in self.postMsgArray {
print(p)
}
and the output from console
A post
Cool post
While this solution works, a Firebaser will quickly point out that reading data like this in a tight loop is generally not recommended. It would be better to have some other correlation between the posts you want to read and then perform a query to read them in.
I've seen a lot of answers to similar questions but none of the methods have worked so far.
if let users = snapshot.value!["users"] as? Dictionary<String,AnyObject> {
each.users = Int(users.count)
var pointsArray = [Dictionary<String,Int>]()
for (key, value) in users {
let uid = key
let points = value["points"] as! Int
pointsArray.append([uid : points])
}
I'm then needing to sort pointsArray by the "points", sort it from high to low, grab the 0th (highest) element, then grab the uid to use.
I've tried:
var myArr = Array(pointsArray.keys)
var sortedKeys = sort(myArr) {
var obj1 = dict[$0] // get ob associated w/ key 1
var obj2 = dict[$1] // get ob associated w/ key 2
return obj1 > obj2
}
This gives me
Value of type [ Dictionary <String,Int>] has no member keys.
I guess that's cause I'm trying to run the sort on my array of dicts vs the dicts themselves? How do I switch this up to get into the actual dictionaries vs. running the sort on the array?
Right - you're not properly accessing the keys of the dictionaries.
Here's a working code:
var pointsArray = [Dictionary<String, Int>]()
pointsArray.append(["1" : 10])
pointsArray.append(["2" : 45])
pointsArray.append(["3" : 30])
// sort by points
let sorted = pointsArray.sort({ $0.first!.1 > $1.first!.1 })
print(sorted) // [["2": 45], ["3": 30], ["1": 10]]
Array(pointsArray.keys) - this doesn't work, because pointsArray is an array, therefore it doesn't have keys property. The contents of pointsArray are dictionaries and they have keys. So you can access the keys of the first dictionary like this: pointsArray[0].keys
might sound like a basic question--but I'm not seeing where I am going wrong..
I end up with either of these two scenarios:
I keep getting the error "Could not cast value of type __NSCFNumber to NSSTring". if I use extractedSku = skuList[i]!.value["sku"] as! String
If I remove as! String it saves it, but it isn't saved as a string. How do I get this to be saved as a string?
I have appended data from firebase into an array
skuArray = [AnyObject?]()
in viewDidLoad, I am iterating skuArray to extract the 'sku' and store into a variable.
var skuArray = [AnyObject?]()
var productDetailArray = [AnyObject?]()
data stored in Sku Array is:
[Optional(Snap (aRandomKey) {
active = 1;
sku = 888888;
})]
viewDidLoad:
let skuList = self.skuArray
for var i = 0; i < skuList.count ; ++i{
let extractedSku = skuList[i]!.value["sku"] as! String
// go into database and extract "products" details by sku
self.databaseRef.child("products/\(extractedSku)").observeEventType(.ChildAdded, withBlock: { (snapshot:FIRDataSnapshot) in
self.productDetailArray.append(snapshot)
})
Since the underlying type is NSNumber, use the stringValue property to get a String:
if let extractedSku = (skuList[i]?.value["sku"] as? NSNumber)?.stringValue {
// use extractedSku which is of type String
}