arraysswiftgroup-bysetnsset

NSSet of elements with coordinates to array of columns/rows


I have a NSSet (from CoreData) containing Element with a column and row properties (both Int16).
I want to efficiently convert this NSSet to an array of array [[Element]] (it would be an array of the columns and the value would be an array of rows in the columns) in a way that it handles holes in coordinates and respect order.

So for example, if I have a the following elements:

let mySet = NSSet([
    Element(column: 1, row: 1, id: 'el1'), 
    Element(column: 3, row: 0, id: 'el2),
    Element(column: 3, row: 2, id: 'el3'),
    Element(column: 6, row: 12, id: 'el4'),
    Element(column: 6, row: 6, id: 'el5),
    Element(column: 6, row: 1, id: 'el6')
]);
// I would get an array like:
let resultArray = [
  [el1],
  [el2, el3],
  [el6, el5, el4]
]

I tried various solution like Dictionary(grouping: ..), reduce, etc... but can't manage to make it works properly.


Solution

  • The code doesn't compile.

    Dictionary(grouping:by:) is indeed a possible way.


    let resultArray = Dictionary(grouping: mySwiftSet, by: \.column)
        .values
        .map { items in
            items.map(\.id).sorted()
        }
        .sorted(by: {$0.first! < $1.first!})
    

    or with reduce(into:)

    let resultArray = Dictionary(grouping: mySwiftSet, by: \.column)
        .reduce(into: [[String]]()) {
            $0 += [$1.value.map(\.id).sorted()]
        }
        .sorted(by: {$0.first! < $1.first!})
    

    Or you can get a nested array of Element, the inner array sorted by row and the outer by column.

    let resultArray = Dictionary(grouping: mySwiftSet, by: \.column)
        .reduce(into: [[Element]]()) {
            $0 += [$1.value.sorted(by:{$0.row < $1.row} )]
        }
        .sorted(by: {$0.first!.column < $1.first!.column})