1

リスト内で一致を見つけ、一致に応じて値を返したいと思います。CollectFirst は、コレクションの要素の照合にはうまく機能しますが、この場合、要素自体ではなく、要素のメンバー swEl で照合したいと考えています。

abstract class CanvNode (var swElI: Either[CSplit, VistaT])
{         
  private[this] var _swEl: Either[CSplit, VistaT] = swElI
  def member = _swEl
  def member_= (value: Either[CSplit, VistaT] ){ _swEl = value; attach}
  def attach: Unit
  attach

  def findVista(origV: VistaIn): Option[Tuple2[CanvNode,VistaT]] = member match
  {
    case Right(v) if (v == origV) => Option(this, v) 
    case _ => None
  }
}

def nodes(): List[CanvNode] = topNode :: splits.map(i => List(i.n1, i.n2)).flatten

//Is there a better way of implementing this? 
val temp: Option[Tuple2[CanvNode, VistaT]] = 
  nodes.map(i => i.findVista(origV)).collectFirst{case Some (r) => r}

その上にViewが必要ですか、それともcollectFirstメソッドはコレクションが必要に応じてのみ作成されるようにしますか?

これはかなり一般的なパターンに違いないと思います。もう 1 つの例は、メイン List の要素の List メンバーがあり、4 番目の要素があればそれを返したい場合です。呼び出すことができる標準的なメソッドはありますか? 次のものを作成できない場合:

implicit class TraversableOnceRichClass[A](n: TraversableOnce[A])
{
  def findSome[T](f: (A) => Option[T]) = n.map(f(_)).collectFirst{case Some (r) => r}
}    

そして、上記を次のものに置き換えることができます。

val temp: Option[Tuple2[CanvNode, VistaT]] = 
  nodes.findSome(i => i.findVista(origV))

これは、2.10 より前の使用のために、2.10 の暗黙のクラスを使用します。

class TraversableOnceRichClass[A](n: TraversableOnce[A])
{
  def findSome[T](f: (A) => Option[T]) = n.map(f(_)).collectFirst{case Some (r) => r}
}

implicit final def TraversableOnceRichClass[A](n: List[A]):
  TraversableOnceRichClass[A] = new TraversableOnceRichClass(n)
4

1 に答える 1

1

導入側のノードとして: 説明している操作 (Some存在する場合は最初のものを返し、そうでない場合) は、の「最初の」モノイド インスタンスの下にNoneある のコレクションの合計です。たとえば、Scalaz 6の場合:OptionOption

scala> Stream(None, None, Some("a"), None, Some("b")).map(_.fst).asMA.sum
res0: scalaz.FirstOption[java.lang.String] = Some(a)

または、次のようなものをスコープに入れることもできます。

implicit def optionFirstMonoid[A] = new Monoid[Option[A]] {
  val zero = None
  def append(a: Option[A], b: => Option[A]) = a orElse b
}

そして、その.map(_.fst)部分をスキップします。残念ながら、これらのアプローチはどちらも Scalaz では適切に遅延していないため、ストリーム全体が評価されます (mconcat . map (First . Just) $ [1..]たとえば、Haskell とは異なり、どこでも問題ありません)。


編集: この補足説明の補足として: どうやら Scalaz適切に遅延した を提供してsumrいるようです (ストリームの場合、これらのアプローチはいずれもビューでは機能しません)。たとえば、次のように書くことができます。

Stream.from(1).map(Some(_).fst).sumr

そして、Haskell バージョンのように、あなたの答えを永遠に待たないでください。


ただし、これではなく、標準ライブラリに固執していると仮定します。

n.map(f(_)).collectFirst{ case Some(r) => r }

私は次のように書きますが、これは多かれ少なかれ同等であり、間違いなくより慣用的です。

n.flatMap(f(_)).headOption

たとえば、整数のリストがあるとします。

val xs = List(1, 2, 3, 4, 5)

これを遅延させmap、その要素がいつアクセスされるかを示す副作用のある関数を作成できます。

val ys = xs.view.map { i => println(i); i }

flatMap結果のコレクションに対してOption-returning 関数を使用しheadOption、最初の要素が存在する場合は (安全に) 返すことができます。

scala> ys.flatMap(i => if (i > 2) Some(i.toString) else None).headOption
1
2
3
res0: Option[java.lang.String] = Some(3)

したがって、空でない値にヒットすると、希望どおりにこれが停止することは明らかです。はい、元のコレクションが厳密である場合は、必ずビューが必要になります。それ以外の場合headOption(または) は、前にある(または)collectFirstに戻って停止することができないためです。flatMapmap

あなたの場合、スキップfindVistaして次のようなものでさらに簡潔にすることができます:

val temp = nodes.view.flatMap(
  node => node.right.toOption.filter(_ == origV).map(node -> _)
).headOption

もちろん、これをより明確にするか、単に混乱させるかは好みの問題です。

于 2012-08-29T23:19:47.750 に答える