11

以下をどのように見つけminValueますか?私には独自の解決策がありますが、他の人がそれをどのように行うかを見たいと思っています。

val i1: Option[Int] = ...
val i2: Option[Int] = ...
val defaultValue: Int = ...
val minValue = ?
4

9 に答える 9

9

更新:以下の解決策と回答の解決策の動作が異なることに気づきました。2つの値がある場合に2つの値の最小値を求める質問を読みましたが、回答ではNone、それが含まれているように効果的に扱っています。他の何よりも大きい(のmin)または小さい(の)値。max

具体的には、 i1isSome(1)i2isの場合None、私のソリューションはデフォルト値を返しますが、あなたのソリューションは1を返します。

後者の動作が必要な場合は、のデフォルトの半群インスタンスOption[A]との熱帯半群を使用できますInt。たとえば、Scalaz 7では、次のように記述します。

import scalaz._, Scalaz._

optionMonoid(Semigroup.minSemigroup[Int]).append(i1, i2) getOrElse defaultValue

または次の速記:

Tags.Min(i1) |+| Tags.Min(i2) getOrElse defaultValue

以下のアプリケーションファンクターソリューションほどクリーンではありませんが、それがあなたの問題である場合、それはあなたの問題です。


追加のリストを作成する必要のない、より慣用的な方法は次のとおりです。

(for { x <- i1; y <- i2 } yield math.min(x, y)) getOrElse defaultValue

または、同等に:

i1.flatMap(x => i2.map(math.min(x, _))) getOrElse defaultValue

あなたがしているのは、2つの場所の関数(min)を適用可能なファンクター(Option)に「持ち上げる」ことです。Scalazは、その適用可能なビルダー構文でこれを簡単にします。

import scalaz._, Scalaz._

(i1 |@| i2)(math.min) getOrElse defaultValue

この場合、標準ライブラリソリューションはそれほど洗練されていませんが、これは知っておくと便利な抽象化です。

于 2012-09-28T12:41:54.653 に答える
6

私は次のアプローチを使用して同様の問題を解決しました。両方のオプションに値がある場合は特殊なケースを処理し、それ以外の場合はAPIメソッドを使用しますOption.orElse

val a: Option[Int]  = Some(10)
val b: Option[Int] = Some(20)
val c: Option[Int] = (a, b) match {
  case (Some(x), Some(y)) => Some(x min y)
  case (x, y) => x orElse y
}
于 2015-01-29T18:12:12.907 に答える
3
val minValue: Int = List(i1, i2).flatten.sorted.headOption getOrElse defaultValue
于 2012-09-28T12:22:08.500 に答える
3

私はこれがあなたが求めているものだと思います:

val minValue = List(i1, i2).flatten match {
  case Nil => defaultValue
  case xs => xs.min
}

並べ替えには、単に最大値または最小値を見つけるよりもはるかに多くの処理が必要になるため、避けたいと思いsortedます(ただし、この場合はおそらくそれほど違いはありません)。

于 2012-09-29T05:23:20.030 に答える
2

式にパターンを使用できます。パターンと一致しない値は破棄されます。

(for (Some(x) <- List(None, Some(3))) yield x) max

ただし、List.flattenアプローチほど良くはありません。

于 2012-12-08T20:21:18.793 に答える
1

scalazとmap/for / getOrElseの使用を避けたい場合は、次のようにすることができます。

val minValue = (i1, i2) match {
  case (Some(x), Some(y)) => math.min(x, y)
  case _ => defaultValue
}
于 2012-09-28T16:22:46.700 に答える
1

言及されていない別のオプションは、reduceLeftOption(交換math.maxおよびmath.min必要に応じて)使用することです。

val min = (first ++ second).reduceLeftOption(math.min).getOrElse(defaultValue)

scala> val first = Some(10)
first: Some[Int] = Some(10)

scala> val second: Option[Int] = None
second: Option[Int] = None

scala> val defaultMin = -1
defaultMin: Int = -1

scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res7: Int = 10

scala> val first: Option[Int] = None
first: Option[Int] = None

scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res8: Int = -1

scala> val first = Some(10)
first: Some[Int] = Some(10)

scala> val second = Some(42)
second: Some[Int] = Some(42)

scala> (first ++ second).reduceLeftOption(math.min).getOrElse(defaultMin)
res9: Int = 10
于 2016-10-09T06:48:24.513 に答える
1

Option2つのsをIterablewith Option's++演算子として組み合わせることができます。これによりminOption、(caseによって形成される空のiterableのcaseを適切に処理するためにNone/None)使用し、必要に応じてデフォルト値にフォールバックできますgetOrElse

(optionA ++ optionB).minOption.getOrElse(-1)
// None and None       => -1
// Some(5) and None    => 5
// None and Some(5)    => 5
// Some(5) and Some(3) => 3
于 2019-01-23T23:04:41.893 に答える
0

tl; dr

カスタム猫 Semigroupインスタンスを使用して、エレガントに必要なことを行うことができます。

import cats.kernel.Semigroup
import cats.instances.option._ // this import is for cats std option combiner
import cats.syntax.semigroup._

object Implicits {
 implicit val intMinSemigroup: Semigroup[Int] =
   (x: Int, y: Int) => math.min(x, y)

 implicit val intMaxSemigroup: Semigroup[Int] =
   (x: Int, y: Int) => math.max(x, y)
}
 
import Implicits.intMinSemigroup
// these are results for minSemigroup
// List((Some(1),Some(1),Some(2)), (Some(1),Some(1),None), (None,Some(2),Some(2)), (None,None,None))
//import Implicits.intMaxSemigroup
// these are results for maxSemigroup
// List((Some(1),Some(2),Some(2)), (Some(1),Some(1),None), (None,Some(2),Some(2)), (None,None,None))
   
for {
 maybeA <- Seq(Some(1), None)
 maybeB <- Seq(Some(2), None)
} yield (maybeA, maybeA |+| maybeB, maybeB)

デフォルト値で置換Noneする場合は、combineを2回使用できます。

val defaultValue: Int = 3
val optionMin = for {
  maybeA <- Seq(Some(1), None)
  maybeB <- Seq(Some(2), None)
} yield (maybeA |+| maybeB) |+| Some(defaultValue)
// List(Some(1), Some(1), Some(2), Some(3))

使い方

簡単に言うと、同じ型の2つの値を型の1つの値に結合するためのtypeclassSemigroup[A]です。ここでは、std cats (拡張)をここで使用します。ソースコード:AAOptionMonoidSemigroup[Option[A]]

class OptionMonoid[A](implicit A: Semigroup[A]) extends Monoid[Option[A]] {
  def empty: Option[A] = None
  def combine(x: Option[A], y: Option[A]): Option[A] =
    x match {
      case None => y
      case Some(a) =>
        y match {
          case None    => x
          case Some(b) => Some(A.combine(a, b))
        }
    }
}

彼自身でオプションのマッチングが必要であり、私たちが彼に仕事をさせるために与えるべきものはすべてですimplicit A: Semigroup[A]min私たちの場合、maxケース用に2つの異なるコンバイナーを記述します。

object Implicits {
 implicit val intMinSemigroup: Semigroup[Int] =
   (x: Int, y: Int) => math.min(x, y)

 implicit val intMaxSemigroup: Semigroup[Int] =
   (x: Int, y: Int) => math.max(x, y)
}

したがって、コンバイナ(つまりimport Implicits.intMinSemigroup)をインポートし、combine関数を演算子として使用するcats.syntax.semigroupために使用します。|+|

maybeA |+| maybeB

結論として、 (だけでなく)任意のタイプのカスタムセミグループを定義し、いくつかのcats構文インスタンスをインポートした後にこのタイプのオプションを組み合わせることができます。Int

于 2021-04-08T14:40:17.903 に答える