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.
Related
I just wanna get all the records from the transaction variable and save it to an array.i tried and all I am getting is this constant error. please help me, I just wanna all models(records) to be saved on an array.
Type '()' cannot conform to 'View'
#State private var transactions: [Transactions] = [Transactions]()
ForEach(transactions, id: \.self) { transaction in
timexxx[0] = transaction.timexx ?? "0"
Text(timexxx[0] ?? "0")
}
enter image description here
Like what #multiverse has suggested
ForEach loop expects some sort of View but you are giving it or attempting to give an "array" (it only wants View)
Here is an updated code where you give the ForEach what it wants and you append to your timexxx array
ForEach(Array(transactions.enumerated()), id: \.offset) { (offset, transaction) in
Text(transaction.timexx ?? "\(offset)")
.onAppear {
timexxx[offset] = transaction.timexx ?? "\(offset)"
}
}
Update
for your question
"how do I do this with a simple "For" loop ? let's say I wanna do this operation in a simple class."
This is how it's done.
I removed the view Text.
for (i, transaction) in transactions.enumerated() {
timexxx[i] = transaction.timexx ?? "0"
}
Ok , so this is an error i faced as well, when i was learning SwiftUI( i am still a beginner), so now we need to understand , what does this error actually means, in this case the ForEach loop expects some sort of View but you are giving it or attempting to give an "array" (it only wants View)....
If you want values to be transferred to an array just simply create a function and do it .....
say you have a class and inside of which you do
#Published var song = [Song]()
then what you do is inside a function like loadData()
objects is the array whose elements you want transferred and most likely those elements belong to a Struct like Song here(if not its even simpler just use what ever type it has like Int, String etc.), this way all your elements will get transferred to song from objects
func loadData() {
song = objects.map {
artist in
Song(album: artist.album, artistImage: artist.artistImage)
}
}
Here i add the simplest possible way to transfer from one array to other
var objects = [1,2,3,4,5]
var song = [Int]()
func loadData() {
song = objects.map { $0 }
}
loadData()
print(song)
//[1,2,3,4,5]
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 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.
i have a struct array that i want "break up" into smaller arrays that can be called as needed or at least figure out how i can map the items needed off one text value.
the struct:
struct CollectionStruct {
var name : String
var description : String
var title : String
var image : PFFile
var id: String
}
and the array made from the struct
var collectionArray = [CollectionStruct]()
var i = 0
for item in collectionArray {
print(collectionArray[i].name)
i += 1
}
printing partArray[i].name gives the following result:
pk00_pt01
pk00_pt02
pk00_pt03
pk01_pt01
pk01_pt02
pk01_pt03
pk01_pt04
pk01_pt05
pk01_pt06
pk01_pt07
pk01_pt08
this is just some test values but there could be thousands of entries here so i wanted to filter the entire array just by the first 4 characters of [i].name i can achieve this by looping through as above but is this achievable using something like .map?
I wanted to filter the entire array just by the first 4 characters of
[i].name
You can achieve this by filtering the array based on the substring value of the name, as follows:
let filteredArray = collectionArray.filter {
$0.name.substring(to: $0.name.index($0.name.startIndex, offsetBy: 4)).lowercased() == "pk00"
// or instead of "pk00", add the first 4 characters you want to compare
}
filteredArray will be filled based on what is the compared string.
Hope this helped.
If you want to group all data automatically by their name prefix. You could use a reducer to generate a dictionary of grouped items. Something like this:
let groupedData = array.reduce([String: [String]]()) { (dictionary, myStruct) in
let grouper = myStruct.name.substring(to: myStruct.name.index(myStruct.name.startIndex, offsetBy: 4))
var newDictionart = dictionary
if let collectionStructs = newDictionart[grouper] {
newDictionart[grouper] = collectionStructs + [myStruct.name]
} else {
newDictionart[grouper] = [myStruct.name]
}
return newDictionart
}
This will produce a dictionary like this:
[
"pk00": ["pk00_pt01", "pk00_pt02", "pk00_pt03"],
"pk01": ["pk01_pt01", "pk01_pt02", "pk01_pt03", "pk01_pt04", "pk01_pt05", "pk01_pt06", "pk01_pt07"],
"pk02": ["pk02_pt08"]
]
Not sure if i am understanding you correctly but it sounds like you are looking for this...
To create a new array named partArray from an already existing array named collectionArray (that is of type CollectionStruct) you would do...
var partArray = collectionArray.map{$0.name}
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) }