Как преобразовать массив в 2d массив, используя Reduce (в: _ :)? - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть массив пользовательских моделей:

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

как:

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")]

Я хочу преобразовать array в двухмерный массив, каждый массив должен содержать события одного дня; Согласно 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")]
]

Первый массив - во внешнем двумерном массиве - содержит события для дня 1, а второй - события для дня 2.

Есть ли способ получить вышеуказанный результат, используя метод reduce(into:_:)?


Несмотря на то, что я хотел сделать это с помощью reduce(into:_:), мне удалось добиться с помощью:

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

Ответы [ 3 ]

0 голосов
/ 05 ноября 2018

Если вы все еще хотите 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]]
        }
}
0 голосов
/ 05 ноября 2018

Чтобы сделать это проще, вы можете использовать комментарий @ MartinR:

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

Но могут быть некоторые дополнительные операции, которые вы хотите выполнить над ним, скажем, сортировка. Тогда вы можете использовать следующий подход:

  1. Группировать данные на основе параметра day. Результат будет [Int: [Event]]

    let grouped = Dictionary(grouping: array, by: { $0.day })
    
  2. Сортировка сгруппированных данных по ключу. результат будет [Int: [Event]]

    let sorted = grouped.sorted(by: { $0.key < $1.key })
    
  3. Вы можете использовать reduce, чтобы получить вывод в нужном формате, обратите внимание, что простое применение reduce сгладит массив, поэтому используйте { $0 + [$1.value] } вместо.

    let resultArray: [[Event]] = sorted.reduce([]) { $0 + [$1.value] }
    
0 голосов
/ 05 ноября 2018

Вы можете использовать группирование функциональность Словарь для достижения ваших требований:

// 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)")
}
...