Let's say that I have this code:
class Stat {
var statEvents : [StatEvents] = []
}
struct StatEvents {
var name: String
var date: String
var hours: Int
}
var currentStat = Stat()
currentStat.statEvents = [
StatEvents(name: "lunch", date: "01-01-2015", hours: 1),
StatEvents(name: "dinner", date: "02-01-2015", hours: 2),
StatEvents(name: "dinner", date: "03-01-2015", hours: 3),
StatEvents(name: "lunch", date: "04-01-2015", hours: 4),
StatEvents(name: "dinner", date: "05-01-2015", hours: 5),
StatEvents(name: "breakfast", date: "06-01-2015", hours: 6),
StatEvents(name: "lunch", date: "07-01-2015", hours: 7),
StatEvents(name: "breakfast", date: "08-01-2015", hours: 8)
]
I would like to know if there's a way to get an array with an output like this:
- [0]
- name : "lunch"
- date
- [0] : "01-01-2015"
- [1] : "04-01-2015"
- [2] : "07-01-2015"
- hours
- [0] : 1
- [1] : 4
- [2] : 7
- [1]
- name : "dinner"
- date
- [0] : "02-01-2015"
- [1] : "03-01-2015"
- [2] : "05-01-2015"
- hours
- [0] : 2
- [1] : 3
- [2] : 5
- [2]
- name : "breakfast"
- date
- [0] : "06-01-2015"
- [1] : "08-01-2015"
- hours
- [0] : 6
- [1] : 8
As you can see, the final array should be grouped by "name" descendant. @oisdk can you please check this out??
This might seem like overkill but it's the solution that entered my mind.
extension Array {
/**
Indicates whether there are any elements in self that satisfy the predicate.
If no predicate is supplied, indicates whether there are any elements in self.
*/
func any(predicate: T -> Bool = { t in true }) -> Bool {
for element in self {
if predicate(element) {
return true
}
}
return false
}
/**
Takes an equality comparer and returns a new array containing all the distinct elements.
*/
func distinct(comparer: (T, T) -> Bool) -> [T] {
var result = [T]()
for t in self {
// if there are no elements in the result set equal to this element, add it
if !result.any(predicate: { comparer($0, t) }) {
result.append(t)
}
}
return result
}
}
let result = currentStat.statEvents
.map({ $0.name })
.distinct(==)
.sorted(>)
.map({ name in currentStat.statEvents.filter({ $0.name == name }) })
Now you have a list of lists, where the first list is contains all the statEvents of the dinner type, the next list contains the events of the lunch type, etc.
The obvious disadvantage is that this is probably less performant than the other solution. The nice part is that you don't have to rely on parallel arrays in order to get the hours that are associated a particular date.
My take:
extension StatEvents : Comparable {}
func < (lhs:StatEvents, rhs:StatEvents) -> Bool {
if lhs.name != rhs.name {
return lhs.name > rhs.name
} else if lhs.date != rhs.date {
return lhs.date < rhs.date
} else {
return lhs.hours < rhs.hours
}
}
func == (lhs:StatEvents, rhs:StatEvents) -> Bool {
return lhs.name == rhs.name
&& lhs.date == rhs.date
&& lhs.hours == rhs.hours
}
struct ResultRow {
var name: String
var dates: [String]
var hours: [Int]
}
var result : [ResultRow] = []
let sorted = currentStat.statEvents.sort()
for event in sorted {
if result.last?.name != event.name {
result.append(ResultRow(name: event.name, dates: [], hours: []))
}
result[result.endIndex - 1].dates.append(event.date)
result[result.endIndex - 1].hours.append(event.hours)
}
Test:
for r in result { print(r) }
prints:
p.ResultRow(name: "lunch", dates: ["01-01-2015", "04-01-2015", "07-01-2015"], hours: [1, 4, 7])
p.ResultRow(name: "dinner", dates: ["02-01-2015", "03-01-2015", "05-01-2015"], hours: [2, 3, 5])
p.ResultRow(name: "breakfast", dates: ["06-01-2015", "08-01-2015"], hours: [6, 8])
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With