2

I have an array of custom model:

struct Event {
    var day: Int // let's assume its Int for now
    var title: String
}

as:

let array = [Event(day: 1, title: "Pizza Party!"),
             Event(day: 1, title: "Another Pizza Party"),
             Event(day: 2, title: "Cinema - Moive 01"),
             Event(day: 2, title: "Cinema - Moive 02")]

I want to transform array to be a 2 dimensional array, each array should contains events that have the same day; According to array, the result should be:

[
    [Event(day: 1, title: "Pizza Party!"), Event(day: 1, title: "Another Pizza Party")]
    [Event(day: 2, title: "Cinema - Moive 01"), Event(day: 2, title: "Cinema - Moive 02")]
]

The first array -in the outer 2d array- contains events for day 1 and the second one contains events for day 2.

Is there a way to get the above result using the reduce(into:_:) method?


Despite of wanting to do it using reduce(into:_:), I was able to achieve by implementing:

func transfrom(_ models: [Event]) -> [[Event]] {
    let uniqueDates = Set(array.map { $0.day }).sorted()
    var twoDArray = [[Event]]()

    for date in uniqueDates {
        var array = [Event]()
        for model in models {
            if date == model.day {
                array.append(model)
            }
        }

        twoDArray.append(array)
    }

    return twoDArray
}

let transfomredArray = transfrom(array) // wanted result
7
  • Why reduce(into:_:) ? Something like Array(Dictionary(grouping: array, by: { $0.day }).values) should do the trick. Commented Nov 5, 2018 at 14:27
  • What makes you think that reduce(into:-:) is suitable for the task? I mean, is it really a requirement? Commented Nov 5, 2018 at 14:33
  • You can't do what you want using reduce(into:_:) Reduce reduces all the elements of an array into a single value. D V's answer of using dictionary(grouping:) should work. Commented Nov 5, 2018 at 14:38
  • Related (duplicate?): stackoverflow.com/questions/31220002/… Commented Nov 5, 2018 at 14:49
  • @DuncanC I beg to differ Commented Nov 5, 2018 at 15:01

3 Answers 3

4

You can use the grouping functionality of Dictionary to achieve your requirement:

// This dictionary will have all your events grouped based on the day it belongs to.
let dict = Dictionary(grouping: array) { (element) -> Int in
    return element.day
}

// If you need a sorted list of events based on the day.
let groupedItems = dict.sorted {
    return $0.key < $1.key
}

// groupedItems would now have all the data, grouped and ready to be used.
for day in groupedItems {
    print("\(day.key): \(day.value.count)")
}
Sign up to request clarification or add additional context in comments.

Comments

0

If you still want reduce(into:):

let result: [[Event]] = array.sorted { $0.day < $1.day }
    .reduce(into: [[Event]]())
    { tempo, event in
        if let lastArray = tempo.last {
            if lastArray.first?.day == event.day {
                let head: [[Event]] = Array(tempo.dropLast())
                let tail: [[Event]] = [lastArray + [event]]
                tempo = head + tail
            }
            else {
                tempo.append([event])
            }
        } else {
            tempo = [[event]]
        }
}

Comments

0

To do it in simpler way, you can use @MartinR's comment:

let resultArray = Dictionary(grouping: array, by: { $0.day }).values

But there might be some extra operations you want to perform over it, lets say sorting. Then you can use following approach:

  1. Group the data, based on day parameter. Result would be [Int: [Event]]

    let grouped = Dictionary(grouping: array, by: { $0.day })
    
  2. Sort the grouped data on basis of key. result would be [Int: [Event]]

    let sorted = grouped.sorted(by: { $0.key < $1.key })
    
  3. You can use reduce to get output in desired format, note that simply applying reduce will flatten the array so use { $0 + [$1.value] } instead.

    let resultArray: [[Event]] = sorted.reduce([]) { $0 + [$1.value] }
    

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.