Reputation: 916
I have some array, and I need to find minimal non zero integer in each row. Is there a way of doing it with min(by:)?
for example
var row = [0,0,0,0,0,0,0,0,1,3,5,6,9]
so I need to get 1
by doing row.min(
) I always get 0.
I was told that I can do it with min{by:}
but I don't fully understand the syntax.
Upvotes: 4
Views: 1387
Reputation: 63321
Just filter your array to keep all elements greater than 0
, and find the min
among those.
Use a lazy
operation to prevent the intermediate array allocation usually caused by Array.filter(_:)
. See https://stackoverflow.com/a/51917427/1630618 for more details.
let minNonZeroValue = row.lazy.filter { 0 < $0 }.min()
Upvotes: 6
Reputation: 12208
You can filter the array for desired values, and use Array.min()
method, like so
row.filter{ $0 > 0 }.min()
Or following will only work if array has ordered numbers
row.first(where: { $0 > 0 })
Upvotes: 8
Reputation: 42149
There are obviously many ways, one way (which doesn't create an intermediate array, or require row
to be sorted) is with reduce
:
row.reduce(nil as Int?) { minSoFar, this in
guard this != 0 else { return minSoFar }
guard let minSoFar = minSoFar else { return this }
return min(minSoFar, this)
}
Which is equivalent to, but more readable than, the shorter:
row.reduce(nil as Int?) { $1 != 0 ? min($0 ?? $1, $1) : $0 }
The result is optional, since there might not be any non-zero elements.
edit: The min(by:)
solution could also indeed be used, but it is also somewhat unreadable and returns 0
in case there are no non-zero elements (instead of nil
):
row.min { $0 == 0 ? false : ($1 == 0 ? true : $0 < $1) }
Upvotes: 2
Reputation: 31655
You could do it like this:
let result = row.lazy.filter { $0 > 0 }.min()
Note that result
is an optional Int
since result
might not contain any element that matches the condition.
Upvotes: 3