I got two arrays from API call,
One is nameArray - which contains recipe names ( menuNameArray = ["pohe","bread","cheese chilli toast"]
And another array - which contains prices of those recipes (menuPriceArray = ["10", "40", "120"].
I have got theses two arrays from API call.
I am displaying both the arrays on the table view & I am searching through the menuNamesArray because I want to search by recipe names.
I am getting recipe names by searching those from menuNameArray. Now I want menuPriceArray to get updated also according to searched menuName Array.
means if I search for "bread" then I must get price value as "40" and accordingly for other names also.
How should I perform such filtering on the second array?
My code Snippet -
//MARK: UISearch result update delegate
func updateSearchResults(for searchController: UISearchController) {
// here arrFilter is the resulting array to sotre searched items from menuNamesArray
arrFilter.removeAll(keepingCapacity: false)
let searchPredicate = NSPredicate(format: "SELF CONTAINS[c] %#", searchController.searchBar.text!)
let array = (menuNamesArray as NSArray).filtered(using: searchPredicate)
let result = menuPriceArray.firstIndex(of: array.startIndex)
arrFilter = array as! [String]
self.tblSearch.reloadData()
//here now I got the searched menu names, Now I want prices for searched menu names from menuPrice Array..
}
Never use multiple arrays as data source.
Swift is an object oriented language. Take advantage of it.
Create a struct
struct Menu {
let name : String
let price : Double
}
and a data source array
var menues = [Menu]()
Filter the array by name and get the price, pretty easy and straightforward
if let foundMenu = menues.filter(where: {$0.name == "bread"}) {
print(foundMenu.price)
}
You can merge the two arrays into one array of dictionary elements.
Related
I'm trying to filter a set of objects based on values in one of their elements based on another array. I've got it working with filter just fine if the search is "OR" - it returns give me all objects for which at least one of the strings in the search array is found.
But I can't figure out how to make it work as an AND search - returning only the objects that match ALL of the strings in the search array.
Example:
struct Schedule {
let title: String
let classTypes: [String]
}
let schedule1 = Schedule(title: "One", classTypes: ["math","english","chemistry","drama"])
let schedule2 = Schedule(title: "Two", classTypes: ["pe","math","biology"])
let schedule3 = Schedule(title: "Three", classTypes: ["english","history","math","art"])
let schedules = [schedule1, schedule2, schedule3]
let searchArray = ["math", "english"]
//works for OR - "math" or "english"
var filteredSchedules = schedules.filter { $0.classTypes.contains(where: { searchArray.contains($0) }) }
I'd like to find a way for it to use the same search array
let searchArray = ["math", "english"]
But only return items 1 & 3 - as they both have BOTH math and english in the list.
There are good examples of AND conditions when the AND is across different search criteria: car type and colour - but I've been unable to find an example where the criteria are dynamically based on items in an array. For context, I could have dozens of schedules with 20+ class types.
You can work with a Set, isSubset will return true if the schedules element contains all elements of the searchSet
let searchSet = Set(searchArray)
var filteredSchedules = schedules.filter { searchSet.isSubset(of: $0.classTypes) }
As suggested by #LeoDabus it might be worth changing the type of classTypes to Set instead of arrays (if order doesn't matter) since they seems to be unique and then the filtering can be done in the opposite way without the need to convert searchArray each time
var filteredSchedules = schedules.filter { $0.classTypes.isSuperset(of: searchArray) }
I am currently struggling with obtaining a value from an array inside an array of dictionaries. Basically I want to grab the first "[0]" from an array stored inside an array of dictionaries. This is basically what I have:
var array = [[String:Any]]()
var hobbies:[String] = []
var dict = [String:Any]()
viewDidLoad Code:
dict["Name"] = "Andreas"
hobbies.append("Football", "Programming")
dict["Hobbies"] = hobbies
array.append(dict)
/// - However, I can only display the name, with the following code:
var name = array[0]["Name"] as! String
But I want to be able to display the first value in the array stored with the name, as well. How is this possible?
And yes; I know there's other options for this approach, but these values are coming from Firebase (child paths) - but I just need to find a way to display the array inside the array of dictionaries.
Thanks in advance.
If you know "Hobbies" is a valid key and its dictionary value is an array of String, then you can directly access the first item in that array with:
let hobby = (array[0]["Hobbies"] as! [String])[0]
but this will crash if "Hobbies" isn't a valid key or if the value isn't [String].
A safer way to access the array would be:
if let hobbies = array[0]["Hobbies"] as? [String] {
print(hobbies[0])
}
If you use a model class/struct things get easier
Given this model struct
struct Person {
let name: String
var hobbies: [String]
}
And this dictionary
var persons = [String:Person]()
This is how you put a person into the dictionary
let andreas = Person(name: "Andreas", hobbies: ["Football", "Programming"])
persons[andreas.name] = Andreas
And this is how you do retrieve it
let aPerson = persons["Andreas"]
Goal: I have two different classes, and two arrays containing members of each class. Using Swift 2.0, I would like to find the unique members of one array compared to the other based on specific attributes of each class.
Example:
class A {
var name: String
init(name: String) {
self.name = name
}
}
class B {
var title: String
init(title: String) {
self.title = title
}
}
let aArray = [A(name:"1"), A(name:"2"), A(name:"3"), A(name:"4")]
let bArray = [B(title:"1"), B(title:"2"), B(title:"5")]
So, I'm looking for some operation between aArray and bArray which returns the 3rd and 4th element of aArray, because they are uniquely in aArray, where the basis of comparison is the attributes A.name and B.title.
Of course, reversing the order of the operation would pick out the 3rd element of bArray, because it is uniquely in bArray.
I know I can accomplish the goal straightforwardly using a simple for loop, but I was hoping for something more elegant and more optimized. But if a for loop is as fast or faster than anything fancier, I'm happy to use it just as well.
I'm not sure fancy or elegant this code is, but, we could do something like this:
let mappedArray = bArray.map { $0.title }
let filteredArray = aArray.filter { !mappedArray.contains($0.name) }
So when we want the unique elements from aArray, we first map the elements from bArray to get an array of the value we want to actually compare:
let mappedArray = bArray.map { $0.title }
mappedArray is just an array of strings based on the title property of the objects in bArray.
Next, we use the filter method to filter objects from aArray. The filter method returns an array with objects that pass the test in our closure. The test we want to apply is objects that are not contained in the mapped array we just built.
let filteredArray = aArray.filter { !mappedArray.contains($0.name) }
If we want to do it the other way, just change a few things:
let mappedArray = aArray.map { $0.name }
let filteredArray = bArray.filter { !mappedArray.contains($0.title) }
I was wondering how you would go about making a tableView that is based on distance between User and a location. My current way of going about it is to load the PFObjects from Parse (includes 1. Venue Name, 2. Venue Image, 3. Venue Location) and then using the information from the PFObjects to make tuples based on [(Name), (Image), (Distance)]. The distance value is determined through finding the distance from current user location and venue location.
Afterwards I would sort the tuples out by distance ( distance < 10 would be 'near' , distance > 10 would be 'far'). After sorting out the 'near' tuples and 'far' tuples I would append these values into their specific arrays (e.g. nearNameLabel, nearImageLabel) and use these arrays to populate the table.
So far I have been having trouble with properly filling the data into their designated arrays due to concurrency issues (placing things in the right threads). I was wondering if there is a better way of going about this issue? Thanks for your time guys.
Instead of using separate arrays you can design it in object level. Like create a class Venue,
class Venue: NSObject {
var name : String?
var location : CLLocation?
var image : UIImage?
}
Load PFObjects as Venue in a single venueArray.
Then sort it with user location,
func sortArray(venueArray : Array<Venue>, myLocation : CLLocation) -> Array<Venue> {
var sortedArray = sorted(venueArray) {
(obj1, obj2) in
// The downcast to Person is only needed if persons is an NSArray or a Swift Array of AnyObjects
let v1 = obj1 as Venue
let v2 = obj2 as Venue
let distance1 = v1.location?.distanceFromLocation(myLocation)
let distance2 = v2.location?.distanceFromLocation(myLocation)
return distance1 < distance2
}
return sortedArray
}
In Parse, I have a class called Queries. In this class I have a column that is of array type called favorites I would like to display that array in a UITableView The trouble is that the query downloads the favorites array column as one array, instead of multiple.
For example:
Row 1 has ["Bananas"] in favorites column
Row 2 has ["Apples", "Oranges"] in favorites column.
Row 3 has ["Tomatoes"] in favorites column
I would like the tableView to show:
Bananas
Apples, Oranges
Tomatoes
But now its showing:
Bananas
Apples
Oranges
var favorites : [String] = []
let query = PFQuery(className: "Queries")
query.findObjectsInBackground { (object, error) in
if object != nil && error == nil {
if let returnedObjects = object {
for objects in returnedObjects {
let getFavorites = objects["favorites"] as! [String]
self.favorites.append(contentsOf: getFavorites)
self.tableView.reloadData()
}
}
}
}
The tableView is populated like this: cell.favoritesLabel.text = favorites[indexPath.row]
Your favourites variable is a single dimension array, so you should either join values from a single row, or make it a two dimensional array and handle it appropriately.
To join values replace your append line with this one:
self.favorites.append(getFavorites.joined(separator: ", "))
First of all change your favorites array to this
var favorites: [[String]] = []
And change this self.favorites.append(contentsOf: getFavorites)
To this self.favorites.append(getFavorites)
The mistake is that you are appending string to an array of strings ignoring that they came in an array in the first place,
now after that you can reduce your items to one string to set it in the cell
like this
cell.favoritesLabel.text = (favorites[indexPath.row])[1..<array.count].reduce(array[0]) { $0 + ", " + $1 }
Although not strictly relevant to your question, I thought I would mention that the Parse iOS SDK does provide a set of prebuilt UI elements one of which is PFQueryTableViewController.
If you haven't already, it may be worth taking a look at the PFQueryTableViewController section in the docs to see if that would simplify your implementation in this case.