Swift Map ARRAYS by Date Array - ios

Im trying to accomplish this: [Swift2 - Sort multiple arrays based on the sorted order of another INT array
But I have to sort by NSDate array.
// dates are actual NSDates, I pasted strings into my sample
var dates:[NSDate] = [2019-12-20 13:00 +0000, 2019-12-20 13:00 +0000, 2019-12-12 13:00 +0000]
var people:[String] = ["Harry", "Jerry", "Hannah"]
var peopleIds:[Int] = [1, 2, 3, 4]
// the following line doesn't work.
// i tried a few variations with enumerated instead of enumerate and sorted instead of sort
// but with now luck
let sortedOrder = dates.enumerate().sort({$0.1>$1.1}).map({$0.0})
dates = sortedOrder.map({points[$0]})
people = sortedOrder.map({people[$0]})
peopleIds = sortedOrder.map({peopleIds[$0]})

Change your dates declaration from NSDate to Date. Date conforms to Comparable protocol since Swift 3.0. Doing so you can simply sort your dates dates.sorted(by: >). To sort your arrays together you can zip your arrays, sort it by dates and map the sorted elements:
let sortedZip = zip(dates, zip(people, peopleIds)).sorted { $0.0 > $1.0}
let sortedPeople = sortedZip.map{ $0.1.0 }
let sortedIDs = sortedZip.map{ $0.1.1 }

If you are trying to sort associated fields you should really consider using an object oriented approach using some kind of model, however, the following should achieve what you are trying to do:
var n = min(dates.count, people.count, peopleIds.count)
var tuples = (0 ..< n).map { (dates[$0], people[$0], peopleIds[$0]) }
.sorted { $0.0 as Date > $1.0 as Date }
dates = tuples.map{ $0.0 }
people = tuples.map{ $0.1 }
peopleIds = tuples.map{ $0.2 }

Related

How to find sum for each category in an array?

I have an array that contains multiple items. This is a Realm array. It contains data in the following structure:
Results<Entry> <0x7ff04840e1a0> (
[0] Entry {
name = Salary;
amount = 40000;
date = 2020-03-18 16:00:00 +0000;
category = Main Incomes;
entryType = Income;
},
[1] Entry {
name = Diff;
amount = -500;
date = 2020-04-18 16:00:00 +0000;
category = Misc;
entryType = Expense;
},
[2] Entry {
name = Cat Food;
amount = -399;
date = 2020-04-18 16:00:00 +0000;
category = Animals;
entryType = Expense;
},
[3] Entry {
name = Fish Food;
amount = -599;
date = 2020-04-18 16:00:00 +0000;
category = Animals;
entryType = Expense;
}
)
What I am trying to achieve is to make another array that will 'pivot' totals for each category. So it can work as a pivot table in Excel.
The desired output is an array that will contain totals for each category:
[0] X-Array {
category = Main Incomes;
amount = XXXX;
},
[1] X-Array {
category = Animals;
amount = XXXX;
And so on...
I'm fairly new to this fancy one-liners like .map and .reduce and other Swift's array management sugar, so would very much appreciate the advice!
Thank you!
P.S. I plan to do the same thing with total expenses and incomes in order to calculate closing balance.
I think use Dictionary is easier to do categorize and later you can convert it to array or anything you want
var dict:[String:Double] = [:]
list.forEach {
if let current = dict[$0.category]{
dict[$0.category] = current + $0.amount
}else{
dict[$0.category] = $0.amount
}
}
print(dict)
I think the question is asking how to get the sum for each category, Income, Expense etc. If so, here's how it's done using the .sum function on the results.
let totalIncome = realm.objects(AccountClass.self)
.filter("entryType == 'Income'")
.sum(ofProperty: "amount") as Int
let totalExpense = realm.objects(AccountClass.self)
.filter("entryType == 'Expense'")
.sum(ofProperty: "amount") as Int
print("Total Income: \(totalIncome)")
print("Total Expense: \(totalExpense)")
and the output for your example data is
Total Income: 40000
Total Expense: 1498
If you want a pivot table, you could just add the amounts to an array - if you need the labels, use a tuple to store them in an array like this
let i = ("Income", totalIncome)
let e = ("Expense", totalExpense)
let tupleArray = [i, e]
for account in tupleArray {
print(account.0, account.1)
}
Keep in mind that a Results object is not an array but has some array-like functions. Results are live updating so as the underlying data in Realm changes, the Results change along with it.

Find Index of Array by NSDate?

I would like to find out the index of an array by an NSDate.
Ill tried:
var sectionsInTable = [NSDate]()
let indexOfElement = sectionsInTable.indexOf(date) // where date is an NSDate in my sectionsInTable Array
print(indexOfElement)
But ill always get false
How is it possible to get the index of an NSDate from an array?
Thanks in advance.
If you have exact copies of NSDate objects, your code should work:
let date = NSDate()
let date2 = date.copy() as! NSDate
var sectionsInTable: [NSDate] = [date]
let indexOfElement = sectionsInTable.indexOf(date2)
print(indexOfElement)
//prints: Optional(0)
Your approach should work fine. This code produces an index of 2:
let s = 31536000.0 // Seconds per Year
var tbl = [NSDate]()
tbl.append(NSDate(timeIntervalSince1970: 40*s)) // 0
tbl.append(NSDate(timeIntervalSince1970: 41*s)) // 1
tbl.append(NSDate(timeIntervalSince1970: 42*s)) // 2
tbl.append(NSDate(timeIntervalSince1970: 43*s)) // 3
let date = NSDate(timeIntervalSince1970: 42*s)
let indexOfElement = tbl.indexOf(date)
The most likely reason that you are not getting the proper index is that your search NSDate has a time component that does not match the time component in NSDate objects in the array. You can confirm that this is the case by printing both objects, and verifying their time component.
Since comparison depends on how deep you want to go with date time thing. I think you should just loop through your date array and compare if it's equal and return that index.

Sort Array of objects according to date

I have an NSMutableArray containing objects and its called HistoryObject, and it has properties date,name,type...etc
i can't find a proper way to sort the array from new to old date for this kind of object.if somebody would explain how can i accomplish that with example !
i have tried the following but its not working:
let sortedArray = HistoryArray.sort({$0.date.compare($1.date) == NSComparisonResult.OrderedAscending })
The date comes in the following format as String : Jun 26, 2016
Do it in this way
// Create your model
class Model {
var date:NSDate!
var name:String!
}
// Not use the NSArray, but use the swift array with sepecific type of data in it
var array = [Model]()
// fake models
for i in 0..<10 {
let model = Model()
model.date = NSDate(timeInterval: Double(i*60), sinceDate: NSDate())
model.name = "\(i)"
array.append(model)
}
// then sort using this code
let newArray = array.sort{ $0.date.timeIntervalSince1970 > $1.date.timeIntervalSince1970 }
You should try it like this,
let sortedArray = HistoryArray.sortInPlace({ $0.date.compare($1.date) == NSComparisonResult.OrderedAscending })
This works fine in Swift2.1
Hope this helps you.

How to sort multiple array based on an array swift?

I would like to sort multiple array based on an array which is array of NSDate
var date = [NSDate]()
var name = [String]()
var job = [String]()
i would like to sort name and job based on the date. Example Like
date = [2016-04-02 01:03:42 +00002,2016-03-02 01:03:42 +0000,2016-05-02 01:03:42 +0000]
name = [john,alex,danson]
job = [engineer,programmer,swimmer]
i would like to sort the date from oldest to the latest then i would like to sort the name and job based on the date . Result Will be Like
date = [2016-03-02 01:03:42 +0000 ,2016-04-02 01:03:42 +0000 , 2016-05-02 01:03:42 +0000 ] //Being Sorted
name = [alex,john,danson]
job = [programmer,engineer,swimmer]
How can i do it ?
extension NSDate {
var day: Int { return NSCalendar.currentCalendar().components(.Day, fromDate: self).day }
}
let result = zip(zip(date, name), jobs).map { ($0.0.0, $0.0.1, $0.1) }.sort { $0.0.day < $1.0.day }
print(result)
This should do it. If you need an explanation, I'll try to explain.
If you want your existing array's to be sorted:
name = name.enumerate().sort { date[$0.index].day < date[$1.index].day }.map { $0.element }
jobs = jobs.enumerate().sort { date[$0.index].day < date[$1.index].day }.map { $0.element }
However, doing this is not safe because if the size of name or jobs is bigger than date, it will crash. You'll have to build some safety inside before using this.
What I forgot to mention is, you could also get the "original" arrays sorted by extracting it from result:
name = result.map { $0.1 }
jobs = result.map { $0.2 }
This is a programming problem instead of Swift problem.
let formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss Z"
let dateStrings = ["2016-03-02 01:04:42 +0000","2016-04-02 01:03:42 +0000" , "2016-05-02 01:03:42 +0000" ]
let date = dateStrings.map {
dateString in formatter.dateFromString(dateString)}
let name = ["alex","john","danson"]
let job = ["programmer","engineer","swimmer"]
let combine = date.enumerate().map {
index, date in
return (date!,name[index],job[index])
}
let result = combine.sort{
$0.0.compare($1.0) == NSComparisonResult.OrderedDescending
}

Finding and combining duplicate entries in an array

Im new here so correct me if I've formatted this incorrectly (also new to swift) but basically what I'm trying to do is take an array of dates and numbers and if any of the dates are the same combine the numbers into one entry.
so this
//This is how i format the data after i pull it from core data
var dateAndEntry = [(String, Double)]
//i've split them into two seperate arrays for sorting, but I feel like theres a better way i don't know
var dates = ["01/01/2016", "02/01/2016", "02/01/2016", "04/01/2016", "05/01/2016", "06/01/2016","07/01/2016","07/01/2016"]
var entries = [-14,2,8,9,-1,8,25,6]
becomes this
var dates = ["01/01/2016", "02/01/2016", "04/01/2016", "05/01/2016", "06/01/2016","07/01/2016"]
var entries = [-14,10,9,-1,8,19]
I've tried doing this but i can only get it so that it makes a new array that only contains the new values rather than allowing me to get the duplicated values, combine, insert at index then delete original entries in the two arrays.
func combineDuplicates(dates: [String]) -> [String]{
var output: [String] = []
var checked = Set<String>()
for date in dates {
if !checked.contains(date) {
checked.insert(date)
output.append(date)
}
}
print(output)
return output
}
let sorted = combineDuplicates(dates)
print(sorted)
and yes i have looked on google and here for answers but turned up nothing.
Any solutions, explanations, help, pointers or references to other questions or sources I may have missed would all be greatly appreciated.
This will get you a dictionary with keys the dates and values the sum of entries for each date:
dates.enumerate().reduce([String:Int]()) { dict, item in
var dict = dict
dict[item.1] = (dict[item.1] ?? 0) + entries[item.0]
return dict
}
// ["06/01/2016": 8, "04/01/2016": 9, "01/01/2016": -14, "05/01/2016": -1, "07/01/2016": 31, "02/01/2016": 10]

Resources