10

私はscalaで次の問題を抱えています。OR の 2 つの条件を持つ述語関数を満たすすべてのリストの最初の要素を見つける必要があります。問題は、要素を取得したいだけでなく、2 つの条件のどちらが満たされているかを知りたいということです。以下に簡単な例を示します。

val l1 = List("A", "B", "AA", "BB")
val l2 = List("AA", "BB", "A", "B")

def c1(s: String) = s.startsWith("B")
def c2(s: String) = s.length == 2

println(l1.find(s => c1(s) || c2(s)))
println(l2.find(s => c1(s) || c2(s)))

結果は次のとおりです。

Some(B)
Some(AA)

l1 の場合、c1 が満たされた (l2 の場合は c2) ことを示す戻り値 (たとえば、文字列) が必要です。考えられる解決策は、テストの前に var を定義し、それを c1 および c2 関数内に設定することですが、より「機能的なスタイル」の解決策を見つけたいと思います。 )。

助けてくれてありがとう

4

3 に答える 3

9

私はこれをします:

スカラ 2.8:

def find2p[T](l: List[T], p1: T => Boolean, p2: T => Boolean) = 
  l.view.map(el => (el, p1(el), p2(el))).find(t => t._2 || t._3)

スカラ 2.7:

def find2p[T](l: List[T], p1: T => Boolean, p2: T => Boolean) = 
  l.projection.map(el => (el, p1(el), p2(el))).find(t => t._2 || t._3)

view/はprojection、マッピングがリスト全体に適用されるのではなく、オンデマンドで行われることを保証します。

于 2010-02-01T10:41:17.973 に答える
3
def find[T](l1 : List[T], c1 : T => Boolean, c2 : T => Boolean) = ((None : Option[(String, T)]) /: l1)( (l, n) => l match {
    case x : Some[_] => l
    case x if c1(n) => Some("c1", n)
    case x if c2(n) => Some("c2", n)
    case _ => None
})

scala> find(l1, c1, c2)
res2: Option[(String, java.lang.String)] = Some((c1,B))

scala> find(l2, c1, c2)
res3: Option[(String, java.lang.String)] = Some((c2,AA))

要件に応じて、返されるラベル文字列のパラメータ Map[T => Boolean, String] を持つことができます:def find[T](l1 : List[T], fs : Map[T => Boolean, String])または独自の演算子を定義します。

これは、見つかった最初の要素の find が中止されたリスト全体を評価します。

于 2010-02-01T10:29:58.200 に答える
1

これは、ダニエル(およびレトロニム)の回答の変形です。

成功した(リストからの)述語だけが必要な場合は、次を使用できます

def findP[T](list: Iterable[T], preds: Iterable[T=>Boolean]) = {
  list.view.map( x => (x , preds.find( _(x) )) ).find( _._2.isDefined )
}

または、名前付き述語のリストを使用できます。

def findP[T](list: Iterable[T],preds: Iterable[(T=>Boolean,String)]) = {
  list.view.map(x => (x , preds.find( _._1(x) ))).find( _._2.isDefined )
}

scala> findP(
     |   List(1,2,3,4,5,6),
     |   List( ((i:Int)=>i>4,"Fred") , ((i:Int)=>(i%6)==0,"Barney"))
     | )
res2: Option[(Int, Option[((Int) => Boolean, String)])] =
  Some((5,Some((<function1>,Fred))))

結果は少し雑然としていますが、簡単にアンラップして、求めていたものを正確に提供できます。

def findP[T](list: Iterable[T],preds: Iterable[(T=>Boolean,String)]) = {
  list.view.map(x => (x , preds.find( _._1(x) ))).find( _._2.isDefined ) match {
    case Some((i,Some((_,s)))) => Some((i,s))
    case _ => None
  }
}

(これは 2.8 のコードです。2.7 では「ビュー」を「プロジェクション」に切り替えます。)

于 2010-02-01T16:38:20.693 に答える