我有一些数组,需要在每行中找到最小的非零整数。是否可以使用min(by:)函数实现?
例如:
var row = [0,0,0,0,0,0,0,0,1,3,5,6,9]
所以我需要得到1。
通过执行 row.min()
,我总是得到0。
有人告诉我可以使用 min{by:}
来实现,但我不完全理解语法。
Array.min()
方法,像这样。row.filter{ $0 > 0 }.min()
如果数组中的数字是按顺序排列的,以下方法才能起作用。
row.first(where: { $0 > 0 })
row.filter({ $0 > 0 })
将产生一个数组作为结果。内存将被分配以存储 [1,3,5,6,9]
。min
将遍历该数组中的数字,挑选出最小值(1
),此后该中间数组不再需要,并将被删除。你要花费 O(row.count)
的时间来复制这些元素,只是为了在短暂使用后立即删除它们。相反,你可以只做 row.filter { 0 < $ 0 } .min()
,并完全跳过中间数组的需求。 - Alexanderrow.lazy.filter { 0 < $0 }.min()
,并完全跳过那个中间数组的需要。 - Alexander只需过滤数组,保留所有大于0
的元素,并在其中找到min
。
使用lazy
操作可防止Array.filter(_:)
通常引起的中间数组分配。有关更多详细信息,请参见https://dev59.com/i1QK5IYBdhLWcg3wZvEs#51917427。
let minNonZeroValue = row.lazy.filter { 0 < $0 }.min()
let result = row.lazy.filter { $0 > 0 }.min()
result
是可选的Int
,因为result
可能不包含任何与条件匹配的元素。显然有很多方法,其中一种方法(不创建中间数组,也不需要对row
进行排序)是使用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)
}
row.reduce(nil as Int?) { $1 != 0 ? min($0 ?? $1, $1) : $0 }
由于可能没有任何非零元素,因此结果是可选的。
编辑: min(by:)
解决方案也确实可以使用,但它也有点难以阅读,并且在没有非零元素的情况下返回 0
(而不是 nil
):
row.min { $0 == 0 ? false : ($1 == 0 ? true : $0 < $1) }