Given a 2D array brightnessMap
which contains [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
, how do find both the highest x numbers, in order (say, x=3 to get 9, 8, 7) AND their positions (2,2 ; 2,1; 2,0)?
Asked
Active
Viewed 82 times
-3

Dávid Pásztor
- 51,403
- 9
- 85
- 116

cannyboy
- 24,180
- 40
- 146
- 252
-
How would you do it given a single array? `[1, 2, 3]`? – Alexander Jan 17 '20 at 14:23
-
don't know. if the numbers were always unique I could do something like `array.index(of: array.max())` to get the highest, but I am not guaranteeing uniqueness. – cannyboy Jan 17 '20 at 14:27
-
Well you can combine the indices with the elements: `zip(array.indices, array)`, and you can then find the max by the elements, while keeping the corresponding indices. – Alexander Jan 17 '20 at 14:30
-
@Alexander-ReinstateMonica Isn't that what `enumerated()` does? :) – Sulthan Jan 17 '20 at 14:37
-
@Sulthan Nope, enumerated is more like `zip(0..., array)`. The resulting indices aren't indices, they're offsets. They always start at 0, and can't be used to index back into the collection, in the general case. Try it on String, or Dictionary, for example. – Alexander Jan 17 '20 at 14:42
-
@Alexander-ReinstateMonica Oh, you are right about that. In case of array they are the same though. – Sulthan Jan 17 '20 at 14:44
-
@Sulthan Yep. But then you have to be careful with things like `a.dropFirst().enumerated()` vs `a.enumerated().dropFirst()`, because they're not the same. – Alexander Jan 17 '20 at 14:57
-
having trouble getting the `zip` to work (does it need to be in a loop?), can u post a code snippet as an answer? – cannyboy Jan 17 '20 at 14:58
2 Answers
1
Maybe not the most elegant solution but it does the job
func maxFromArrays(_ maxCount: Int ) -> [Int: [(Int,Int)]] {
let max3 = array.flatMap {$0}.sorted().suffix(3)
var positions: [Int: [(Int,Int)]] = [:]
for (index, value) in array.enumerated() {
for (index2, value2) in value.enumerated() {
if max3.contains(value2) {
positions[value2, default: []].append((index, index2))
}
}
}
return positions
}
Borrowing makeList
from this answer we can test it with some larger arrays
func makeList(_ n: Int) -> [Int] {
return (0..<n).map { _ in .random(in: 1...20) }
}
let array = [makeList(10), makeList(10), makeList(10)]
print(array)
print(maxFromArrays(3))
[[11, 3, 15, 7, 1, 7, 5, 17, 13, 8], [13, 9, 7, 15, 4, 17, 7, 17, 17, 2], [9, 18, 13, 15, 12, 2, 11, 20, 4, 16]]
[18: [(2, 1)], 17: [(0, 7), (1, 5), (1, 7), (1, 8)], 20: [(2, 7)]]

Joakim Danielson
- 43,251
- 5
- 22
- 52
1
You can use the enumerated
method and the beauty of flat map:
let brightnessMap = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
let count = 3
let result = brightnessMap
.enumerated()
.map { x, elts in elts.enumerated().map { y, value in (pos: (x,y), value: value) } }
.flatMap { $0 }
.sorted { $0.value > $1.value }
.prefix(count)
The result
will contain this array of tuples:
[(pos: (2, 2), value: 9), (pos: (2, 1), value: 8), (pos: (2, 0), value: 7)]

Zaphod
- 6,758
- 3
- 40
- 60