0

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"),
]
2
  • just use map, check this: hackingwithswift.com/example-code/language/… Commented Jan 26, 2022 at 0:23
  • @cristian_064 map is not enough in this case. A bit too complex. OP needs to first reduce/group the collection elements. Commented Jan 26, 2022 at 1:39

2 Answers 2

1

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
    }()
}
Sign up to request clarification or add additional context in comments.

Comments

0

If you are grouping these for grouping these in the UI, I would suggest a few things:

  1. AfterData should use Date, not String.
  2. When you present this in the UI, use a user-friendly date formatter rather than the cryptic yyyy/MM/dd format. E.g., a dateStyle of .medium.
  3. I would use reduce to calculate the totals by day, sort to sort them, and map to create your custom objects.
  4. FWIW, using this pattern, you are no longer dependent upon the input data having already been sorted.

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.