Reputation: 357
I want to convert beforeDataSet to afterDataSet in Swift. Could you tell me how to convert it?
struct BeforeData {
var value: Int
var date: Date
}
struct AfterData {
var sumValue: Int
var dateString: String
}
let beforeDataSet = [
BeforeData(value: 100, date: date1), // 2022-01-01 12:00
BeforeData(value: 150, date: date2), // 2022-01-01 14:11
BeforeData(value: 120, date: date3), // 2022-01-02 07:00
BeforeData(value: 120, date: date4), // 2022-01-02 12:00
BeforeData(value: 200, date: date5), // 2022-01-03 08:00
]
let afterDataSet = [
AfterData(sumValue: 250, dateString: "2022/1/1"),
AfterData(sumValue: 240, dateString: "2022/1/2"),
AfterData(sumValue: 200, dateString: "2022/1/3"),
]
Upvotes: 0
Views: 1677
Reputation: 438407
If you are grouping these for grouping these in the UI, I would suggest a few things:
AfterData
should use Date
, not String
.yyyy/MM/dd
format. E.g., a dateStyle
of .medium
.reduce
to calculate the totals by day, sort
to sort them, and map
to create your custom objects.So, perhaps:
struct BeforeData {
var value: Int
var date: Date
}
struct AfterData {
var sum: Int
var date: Date // note, not `String`
}
let iso = ISO8601DateFormatter()
let date1 = iso.date(from: "2022-01-01T12:00:00Z")!
let date2 = iso.date(from: "2022-01-01T14:11:00Z")!
let date3 = iso.date(from: "2022-01-02T07:00:00Z")!
let date4 = iso.date(from: "2022-01-02T12:00:00Z")!
let date5 = iso.date(from: "2022-01-03T08:00:00Z")!
let before = [
BeforeData(value: 100, date: date1),
BeforeData(value: 150, date: date2),
BeforeData(value: 120, date: date3),
BeforeData(value: 120, date: date4),
BeforeData(value: 200, date: date5)
]
let calendar = Calendar.current
let grouped = before
.reduce(into: [Date: Int]()) { dictionary, object in
let day = calendar.startOfDay(for: object.date)
dictionary[day, default: 0] += object.value
}
.sorted { $0.0 < $1.0 }
.map { AfterData(sum: $0.value, date: $0.key) }
And then:
let formatter = DateFormatter()
formatter.dateStyle = .medium
for value in grouped {
print(formatter.string(from: value.date), value.sum)
}
And a US user will see:
Jan 1, 2022 370
Jan 2, 2022 120
Jan 3, 2022 200
But a UK user will see:
1 Jan 2022 370
2 Jan 2022 120
3 Jan 2022 200
Then we are showing dates in the format with which the end-user is comfortable.
Upvotes: 0
Reputation: 236548
What you need is to reduce your original array (considering their elements are sorted by date) and check if the last date is in the same day as the current element date. If true sum the element value with the last element value otherwise append a new element to the result with the current element value and the formatted date string:
let afterDataSet: [AfterData] = beforeDataSet.reduce(into: []) {
let dateString = Formatter.date.string(from: $1.date)
if let index = $0.indices.last,
$0[index].dateString == dateString {
$0[index].sumValue += $1.value
} else {
$0.append(.init(sumValue: $1.value, dateString: dateString))
}
}
You will need to add these Date Formatter to your project:
extension Formatter {
static let date: DateFormatter = {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: .iso8601)
formatter.locale = .init(identifier: "en_US_POSIX")
formatter.dateFormat = "yyyy-M-d"
return formatter
}()
}
Upvotes: 1