NSSet of elements with coordinates to array of columns/rows

39 views Asked by At

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.

1

There are 1 answers

3
vadian On BEST ANSWER

The code doesn't compile.

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

  • First cast the set to Swift Set<Element>
  • Then group the array to a dictionary by the column property and get the values
  • Finally map all items to the id values and sort the outer array by its first item

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})