Swift - Sort array similar to another - arrays

In my tableview I get my data shown from these arrays:
var offersProduct = [String]()
var offersPrice = [String]()
var savings = [String]()
var shops = [String]()
var imageNames = [String]()
var exDates = [Int]()
var pickedIDs = [String]()
var setDates = [Int]()
Right now the data isn't sorted in any way. So I have 2 questions.
How do I sort arrays after date? Nearest to NSDate first.
I have the array of exDates, witch is an array of Int of timeIntervalSince1970. So i want the closest expiry date to get index 0 of the array.
How do I sort the other arrays like the first one?
So, lets say I have sorted exDates array, that gives me another problem, cause now the expiry date shown, doesn't match with the data from the other arrays. So I need to somehow sort the other arrays, by moving the data in from the same index as in the exDates array. How can that be done?
Hope someone can help.

Your problem is that you use separate entities where single/uniform entity should be used. To achieve what you are trying, you should switch to using class or struct which would encompass all the associated data.
If you proceed with the approach you currently adopt, you are guaranteed to have arbitrary bugs and performing dull operations to synchronize data across all your arrays. So, in essence, having multiple arrays instead of one array of specialized objects is a bad practice.
Consider refactoring your arrays:
struct Entity {
var offerProduct : String
var offerPrice : String
var savings : String
var shop : String
var imageName : String
var exDate : Int
var pickedID : String
var setDate : Int
}
var entities = [Entity]()
Then to sort single array of entities (once filled), you merely set necessary criteria, such as:
entities = entities.sorted(by: {$0.exDate > $1.exDate })

Make a structure:
struct Entry {
let product: String
let price: String
let saving: String
let shop: String
let imageName: String
let exDate: Int
let pickedID: String
let setDate: Int
}
Then use one array of these structures instead of several:
var entries = [Entry]()
You can sort this array easily by one of the structure's fields:
let expiryTimePoint = ...
entries = entries.sorted({
// compare absolute differences of intervals for sorting
return abs($0.exDate - expiryTimeInterval) > abs($1.exDate - expiryTimeInterval)
})

Related

How to transfer new data to array using swift?

I have a tableView(purchases cart), which include magazines in multiple sections. In section, we can see cells with stuff from magazine. In the cell, I did display UILabel(price), UILabel(count) and UILabel with summary price (item * count) in one cell. Also, we can see two buttons (plus and minus), for changing count of item. Example -
var count: Float = Float(cell.countLabel.text!)!
guard Int(count) > 1 else { return }
var shortPrice = cell.newPrice.text
shortPrice?.removeLast(2)
let floatPrice = Float(shortPrice!)
count -= 1
let newSumShortPrice = floatPrice! * count
cell.countLabel.text = String(Int(count))
cell.summPrice.text = "\(newSumShortPrice) ₽"
But changes didn't work with an array.
The strcuct of my model -
struct ViewModel {
var name: String?
var offers: [Offers]?
}
struct Offers : Mappable {
var count : Int?
var fullPrice : String?
var shortPrice : String?
}
var purchasesViewModel = [PurchaseList.Fetch.ViewModel]()
I know, that I must pass changed data (count) to my array and use method tableView.reloadData(). But I can't, because I don't know how to do that.
How I can transfer new count value (check struct Offers) to array purchasesViewModel?
You can go to the index of the array and delete the particular data(old data) from purchasesViewModel and recreate new data and insert it on that index. I hope this will work.

Sorting a dictionary by key and converting it into an array

I have a dictionary of prices and quantities. I am getting updates on the price and values multiple times in a second so I don't want to store them in an array because dictionary are much faster.
let mainPriceValDict = [Double:Double]()
The data is coming in as an array of JSON so I am using codable to parse the JSON and put it into a dictionary. When I use the data, it needs to be sorted in ascending and/or descending order because I am looping through each price in order to get to a certain total quantity. The format that the array is in that I am looping through is as follows:
let loopingArray = [PriceQuantityEntry]()
struct PriceQuantityEntry {
let price : Double
let size : Double
}
I want to sort the prices which are the keys in the dictionary above and convert them into an array of PriceQuantityEntry. What is the best way to do this? In ascending and deciding order. I have tried first getting all the keys sorted and then grabbing associated values and putting them into the array in order but this seems like more processing than this task actually requires.
I think the best way to do this would be to put a custom initializer in the struct to convert the dictionary value to a value of type PriceQuantityEntry but I am not exactly sure how that would work with the sorting.
This is what I am currently doing to get it to work. I just feel like there is a more efficient way for it to be done. If you feel like I should keep the structure as an array instead of converting it to a dict, let me know.
loopingArray = self.mainPriceValDict.sorted { $0.0 < $1.0 }.map { PriceQuantityEntry(price: $0.0, size: $0.1) }
If you are getting a lot of updates to individual entries, both a dictionary and an array may cause memory copies of the whole memory structure every time an entry is changed.
I would suggest using objects (classes) instead of structures. This will allow you to use both an array and a dictionary to reference the object instances. The dictionary will provide direct access for updates and the array will allow sequential processing in forward or backward order.
[EDIT] Example:
class PriceQuantityEntry
{
static var all:[PriceQuantityEntry] = []
static var prices:[Double:PriceQuantityEntry] = [:]
var price : Double
var size : Double
init(price:Double, size:Double)
{
self.price = price
self.size = size
PriceQuantityEntry.all.append(self)
// PriceQuantityEntry.all.resort() // on demand or when new prices added
PriceQuantityEntry.prices[price] = self
}
class func update(price:Double, with size:Double)
{
if let instance = PriceQuantityEntry.prices[price]
{ instance.size = size }
else
{
let _ = PriceQuantityEntry(price:price, size:size)
PriceQuantityEntry.resort()
}
}
class func resort()
{
PriceQuantityEntry.all.sort{$0.price < $1.price}
}
}
// if adding multiple initial entries before updates ...
let _ = PriceQuantityEntry(price:1, size:3)
let _ = PriceQuantityEntry(price:1.25, size:2)
let _ = PriceQuantityEntry(price:0.95, size:1)
PriceQuantityEntry.resort()
// for updates ...
PriceQuantityEntry.update(price:1, with: 2)
// going throug list ...
var count:Double = 0
var total:Double = 0
var quantity:Double = 5
for entry in PriceQuantityEntry.all
{
total += min(entry.size,quantity-count) * entry.price
count = min(quantity,count + entry.size)
if count == quantity {break}
}

swift - using .map on struct array

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}

Swift: Accessing array value in array of dictionaries

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"]

Populating a tableView based on user distance form venue Location in Swift+Parse

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
}

Resources