- Xcode 6.2 beta 4
- Playground
上限値
値が◯◯を超えないようにしたい(=値が◯◯以下になるように抑えたい) とき。
例えば、
「車の速度を加速させるけど、時速 60km は絶対に超えないようにしたい」
...みたいな場合に使用します(良い例が思いつきませんでした)。
学校で習いそうな書き方は以下のようなものでしょうか。
import UIKit
let upperLimit = 60.0
var speed = 50.0
speed += 50.0 // なんかの計算。ここでは"100.0"となる
if speed > upperLimit {
speed = upperLimit
}
println(speed) // "60.0"
上記のコードでも全く問題無いのですが、通な(?)プログラマは以下のようにmin
関数を用いていると思います。
import UIKit
let upperLimit = 60.0
var speed = 50.0
speed = min(speed + 50.0, upperLimit) // なんかの計算&上限値込み
println(speed) // "60.0"
比較的短く書ける(値と上限値の登場回数が少なくて済む)ところにメリットがあるのかなと思われます(厳密な所はわかりませんが)。
上限値を超えた時(または上限値に達した時)に値の補正以外に何か別の処理を書きたい場合は前者のコードになると思いますが、単純な計算結果などに上限値を設ける場合は後者の方がよく利用するかなと思います。
若かりし頃、「上限」値を設けるためになんとなく逆の意味っぽい「min
」関数を使うという違和感に悩まされましたが、慣れればなんてことはありません。
下限値
値が◯◯より小さくならないようにしたい(=値が◯◯以上になるように抑えたい) とき。
例えば、
「画像のアスペクト比を固定したままサムネイルを作りたい、このとき、画像の横幅と縦幅は 1 より小さくならないようにしたい(1より小さいとマズイ)」
...みたいな場合に使用します。
今度はmax
関数を使ってやると楽です。
import UIKit
let lowerLimit = 1
let scale = 0.001 // 拡大率(適当)
let oldWidth = 10 // 旧横幅(適当)
let newWidth = max(Int(Double(oldWidth) * scale), lowerLimit) // サムネイルの横幅
println(newWidth) // "1"
上限値&下限値
値が◯◯以上△△以下になるように抑えたい とき。
例え話が思いつきません。
min
関数とmax
関数を組み合わせれば一行で書けます(minとmaxの入れ子の順番はどちらでもよいです)。
値は適当です。
import UIKit
let lowerLimit = 1
let upperLimit = 100
let test = min(max(34 * 56, lowerLimit), upperLimit) // 34 * 56の計算結果を1以上100以下に抑える
println(test) // "100"
...で、ここからが本題。
この記事を書くきっかけは、そもそもこれと同等の処理が一発で出来る関数はswiftには無いの?という疑問がわいた事でした(ざっと探した限りでは見つけられませんでした)。
他のプログラム言語などではclamp
という関数が有るようでして、この関数をswiftで書いてみることにしました。
(clamp
関数の存在自体、Twitterで教えてもらうまで知りませんでした...)
import UIKit
func clamp<T: Comparable>(value: T, lowerLimit: T, upperLimit: T) -> T {
if value < lowerLimit {
return lowerLimit
}
if value > upperLimit {
return upperLimit
}
return value
}
// テスト
println(clamp(4, 1, 100)) // "4"
println(clamp(-4, 1, 100)) // "1"
println(clamp(400, 1, 100)) // "100"
println(clamp(400.0, 1.0, 100.0)) // "100.0"
ジェネリクスを使っているので、大抵の型で使えると思います。
もし他に良い方法などがあれば教えていただけると幸いです。