Avoid duplicates while adding in dictionary - ios

I have a dictionary in which I'm adding values like so...
var mydictionary = ["id": "", "quantity": "","sellingPrice":""] as [String : Any]
dictionary["id"] = product?.id
dictionary["quantity"] = product?.quantity
dictionary["sellingPrice"] = product?.theRate
And these values I added to an array like so...
self.arrayOfDictionary.append(mydictionary)
But if arrayOfDictionary already contains mydictionary, I don't want to add it. Else, I want to add it.
The basic idea here is to add data from collection view items to array of dictionary. When I click on the buttons that I have on each collection view item the data on it is added to an array of dict. while at the same time showing those data in a tableviewcell. But when I navigate back from the tableview & visit the collectionview items again and click on some other collecn.view item, so as to add them to the array of dictionary as before, then the item that was added initially to the array of dictionary gets added again. This has to be somehow prevented.
As suggested by another SO user something like this was tried to prevent this duplication...
if self.arrayOfDictionary.contains(where: { (dict) -> Bool in
"\(dict["id"] ?? "")" != "\(dictionary["id"] ?? "")"}) {
self.arrayOfDictionary.append(dictionary)
}
But this doesn't seem to work. With this nothing is added to the array and its totally empty. Hope somebody can help...

Try this code to avoid duplication
I hope "id" value will be unique in your dictionary.
var mydictionary = ["id": "1", "quantity": "","sellingPrice":""] as [String : Any]
var arrayOfDictionary = [Dictionary<String, Any>]() //declare this globally
let arrValue = arrayOfDictionary.filter{ (($0["id"]!) as! String).range(of: mydictionary["id"]! as! String, options: [.diacriticInsensitive, .caseInsensitive]) != nil }
if arrValue.count == 0 {
arrayOfDictionary.append(mydictionary)
}

I've got better idea then every time you perform loop to check unique ness.
Maintain one Bool array of same size of your collectionView Items array with predefined false values each.
When you click on button of collection View item, change flag of Bool array with same index. And simultaneously you can disable the button also(if you want). Otherwise whenever user clicks on button, just check flag from Bool array and add Dictionary to new array as needed.
Here, your new array will be performed and you will same process and time of looping also.

One way to approach the problem could be to construct a structure which contains product details:
/// Details Of A Product
struct ProductDetails{
var id: String!
var quantity: Int!
var sellingPrice: Int!
}
Then create a dictionary which stores the product details with the key being the "ID" e.g:
var products = [String: ProductDetails]()
You could then create a product like so:
let productA = ProductDetails(id: "1", quantity: 100, sellingPrice: 10)
To add a unique product to your dictionary you could use a function like this:
/// Adds A Product To The Products Dictionary
///
/// - Parameter product: ProductDetails
func addProductDetails(_ product: ProductDetails){
//1. If A Product Exists Ignore It
if products[product.id] != nil{
print("Product With ID \(product.id!) Already Exists")
}else{
//2. It Doesn't Exist So Add It To The Dictionary
products[product.id] = product
}
}
I tested this quickly and it won't allow products which have duplicate ID's. although of course you could change the parameter as needed.

Related

Compare the two lists and change the value of the properties of the objects in one of the lists

I have the two lists of AddItem objects. AddItem is a custom object made of data downloaded from the web. The second one list is also AddItem, but this one is saved in the database. I use it to create another list, but in this case user of the app decides which object are important for him.
This want I want to achieve is to mark every single object of the first AddItem list (not saved in the database, create during the start of the view), to show in the TableView which one is saved in the database, so I already use him in another view. You know what I mean. There is a TableView list and if I am interested in a cell I select it and add it to the database.
I hope I have described it clearly. If not, ask for questions.
The first AddItem list (not saved in the database):
func setAddItemList(stations: [Station], sensors: [Sensor]) {
var addItems = [AddItem]()
var sensorItems = [SensorItem]()
let falseValue = RealmOptional<Bool>(false)
addList = try persistenceService.fetchAddItems().toArray(ofType: AddItem.self) //The second list with saved data in the database
let addItem = stations.map { station in
AddItem(
id: station.id,
stationId: station.id,
cityName: station.city?.name ?? "",
addressStreet: station.addressStreet!,
added: falseValue,
sensor: [])
}
addItems.append(contentsOf: addItem)
As you can see, it's create by already downloaded data. I decided to add the property - added, which is the bool property and mark it as true if selected the right cell. Unfortunately I don't know how to do this when creating a list of AddItem objects. The saved array is almost the same. There is only more data, but ids, names, addresses and so on are same, so there are loads of the same data for comparison
I made the solution myself:
addItem.forEach { item in
guard let index = addList2.firstIndex(where: { $0.id == item.id})
else {
print("Failed to find the SavedAddItem for the AddItem \(item.id)")
return
}
addItems[index + 1].added = trueValue
}

Append Dictionary, iOS, Swift

I am trying to edit my code that I created that is posting text to firebase. I was originally only allowing 8 pictures and descriptions no more, no less. I am now refactoring so the user can pick any number up to 8. I have the checks for the photos working and it uploads the amount picked. I have put checks in place to see if there is a picture or not and if there is it will show the text box to add a description otherwise it is hidden. My problem is I have a dictionary that posts to firebase that is posting 8 descriptions so if i was to create 2 it would fill the other 6 with "" is there a way to check that if an image is nil like I do above then it adds to the dictionary to upload. My function is below..
func postToFirebase() {
let post: Dictionary<String, AnyObject> = [
"photoInfo1": photoInfo1.text as AnyObject,
"photoInfo2": photoInfo2.text as AnyObject,
"photoInfo3": photoInfo3.text as AnyObject,
"photoInfo4": photoInfo4.text as AnyObject,
"photoInfo5": photoInfo5.text as AnyObject,
"photoInfo6": photoInfo6.text as AnyObject,
"photoInfo7": photoInfo7.text as AnyObject,
"photoInfo8": photoInfo8.text as AnyObject
]
let firebasePost = DataService.ds.REF_BASE.child("posts").child("\(stringPassed)")
firebasePost.updateChildValues(post)
}
The check I'm doing before this to hide the boxes are..
if passImage2 == nil {
photo2.isHidden = true
photoInfo2.isHidden = true
}
and so on.
I was hoping I could do a check to see if the photo is not nil then if so append the "post" dictionary rather than have them all already coded in.
If you don't need your photoInfo to be continuos in numbering, you can use
let filtered = post.filter { (key, value) -> Bool in
guard let stringValue = value as? String else { return false }
return stringValue != ""
}
If you need it to be continuos you can filter an array of label texts and then with using of enumarated and reduce, you can create a new dictionary.

Save tableview textfields to an array of custom objects

I´m searching for a way to save the data a user enters in two textfields in a tableview. The user has to enter the name and the height of person in a tableview and I want to save it to a custom array.
struct PersonData {
var name: String
var height: Int
init(name: String, height: Int) {
self.name = name
self.height = height
}
}
I´ve searched and i found this Swift: retrieving text from a UITextField in a custom UITableViewCell and putting it in an array but still got two questions.
How i add item to my custom array? I try it with this:
personData[textField.tag].name = textField.text!
Isn´t a easier way to do it?
Thank you!!
If I understood your question properly then heres a possible solution.
You initialise an array of type PersonData. Then you make an object of type PersonData. Whenever you have some info, you store it in this object and append the object to the array created.
let array = [PersonData]()
let personDataObject = PersonData()
//After you store the values in the object you add the object to you array.
personDataObject.name = textField1.text
personDataObject.height = textField2.text //You need to convert this to Int. Try personDataObject.height = textField2.text as? Int or personDataObject.height = Int(textField2.text)
array.append(personDataObject)

Add value instead of change value In Firebase with Swift

I would like to save and retrieve features to and from Firebase into a TableView.
The child I would like to save them under is the uid (unique user id)
so a feature would look like this in the database:
Firebase database
The ideal situation, is how the "derde" is saved, so the uid as a key and "derde" as the value.
#IBAction func saveButtonPressed(sender: AnyObject) {
let featureContents = addFeatureTextField.text
if featureContents != "" {
// Build the new Feature.
let newFeature: String = featureContents!
let ref = DataService.dataService.FEATURE_REF.childByAppendingPath(uid)
ref.setValue(newFeature)
where uid is a String, retrieved from authdata somewhere else in the code.
If I save it like this, it saves it to the specific uid path. If I want to add another feature by clicking on the + in the TableViewController, it saves it to the same path, so the Firebase database is updated with the new value and so instead of two features you only end up with one updated feature.
You can prevent this by working with the chilByAutoId() method, to save a list of items. The code would look like this:
#IBAction func saveButtonPressed(sender: AnyObject) {
let featureContents = addFeatureTextField.text
if featureContents != "" {
// Build the new Feature.
let newFeature: String = featureContents!
let ref = DataService.dataService.FEATURE_REF.childByAutoId().childByAppendingPath(uid)
ref.setValue(newFeature)
via this way, a feature is saved, as you can see in the above image at: "vierde"
This allows you to save multiple features with all the same uid, but different autoId.
But, if I save it like this, my tableView stays empty. The TableViewController is like this:
DataService.dataService.FEATURE_REF.observeEventType(.Value, withBlock: { snapshot in
// The snapshot is a current look at our features data.
print("The features in the tableView should be \(snapshot.value)")
self.features = []
if let snapshots = snapshot.children.allObjects as? [FDataSnapshot] {
for snap in snapshots {
// Make our features array for the tableView.
if let postDictionary = snap.value as? String {
print("All in")
let key = snap.key
let feature = Feature(key: key, value: postDictionary)
// Items are returned chronologically, but it's more fun with the newest features first.
self.features.insert(feature, atIndex: 0)
}
}
}
// Be sure that the tableView updates when there is new data.
self.tableView.reloadData()
})
}
Problem lies in this code: if let postDictionary = snap.value as? String {
This conditional binding does not succeed, because the value is not a String, but the autoId key has no value, only the child under it which is the uid has a value "vierde"
Two possible solutions which I am asking you guys:
1) How can I save multiple features with the same uid without using the autoId?
2) If I am obliged to use the autoId, how can I make sure it observes the value of the uid key under the autoId, instead of the non existing value of the autoId.
Thanks for your help!
I think the answer to the question is to build a dictionary out of the key:value pairs of data and store that as a child of your uid node
let featureDict = [ "feature_0": "cool feature", "feature_1": "great feature"]
let ref = DataService.dataService.FEATURE_REF.childByAppendingPath(uid)
ref.setValue(featureDict)
results in
the_uid
feature_0: "cool feature"
feature_1: "great feature"
The limitation here is the key's names, and then the ability to add even more data about each feature.
Here's a potentially better option
the_uid
auto_id_0
feature_name: #"cool feature"
summary: "Everything you'd ever want to know about this feature"
auto_id_1
feature_name: #"great feature"
summary: "Info about this great feature"
The auto_id_x is generated by autoId and allows you to add however many features you want, change their names and summaries. etc. The children of each auto_id_x are (or could be) stored in a dictionary and saved per the above example.

Confused on snippet of code for implementing iCloud behavior on iOS

The code is from a book. In terms of overall app architecture (MVC), it's part of the Model. The model has two main components:
An array of tags called tags
A dictionary of tag - query called searches
The app saves these pieces of data in the NSUserDefaults (iOS defaults system) and on iCloud. The following method is called when a change in iCloud is signaled. The parameter is an instance of NSNotification.userInfo
// add, update, or delete searches based on iCloud changes
func performUpdates(userInfo: [NSObject: AnyObject?]) {
// get changed keys NSArray; convert to [String]
let changedKeysObject = userInfo[NSUbiquitousKeyValueStoreChangedKeysKey]
let changedKeys = changedKeysObject as! [String]
// get NSUbiquitousKeyValueStore for updating
let keyValueStore = NSUbiquitousKeyValueStore.defaultStore()
// update searches based on iCloud changes
for key in changedKeys {
if let query = keyValueStore.stringForKey(key) {
saveQuery(query, forTag: key, saveToCloud: false)
} else {
searches.removeValueForKey(key)
tags = tags.filter{$0 != key}
updateUserDefaults(updateTags: true, updateSearches: true)
}
delegate.modelDataChanged() // update the view
}
}
My question is on the if - else inside the for loop. The for loop iterates over keys that where changed; either the user adds a new search, updates an existing search, or deletes a search. But, I don't understand the logic behind the if-else. Some clarifying thoughts would be appreciated. I've read it over and over but it doesn't tick with me.
if let query = keyValueStore.stringForKey(key)
means that if keyValueStore contains a string corresponding to key, then this string will be assigned to the constant query.
This is called "safe unwrapping":
inside the if let ... condition, the query is safely saved with saveQuery because using if let ... guarantees that the value of keyValueStore.stringForKey(key) won't be nil.
If the value is nil, then in the else branch, the filter method is used to update the tags array without the key we just processed: tags.filter{$0 != key} means "return all items in tags that are different from key" (the $0 represents the current item from the array processed by filter).

Resources