2016-08-11 11 views
2

私は、1と-1を含むリストを持っています。私が後にしている目標は、合計が-1のときにリスト内の位置を見つけることです。リストからfoldLeftで値の位置を見つける方法は?

List[Int] = List(1, -1, 1, -1, 1, 1, -1, 1, -1, 1, -1, 1, 1, 1, 1, 1, -1, -1, -1, 1, -1, 
-1, 1, 1, -1, -1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 1, 1, 1, 1, 
1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1) 

しかし、私のコードは機能しません。

ここに私の試みがあります(読解のためにコードを配置しました)。注:floorは、List of Intsを保持しています。

floor.foldLeft(0) { ((x,y) => x+y == -1) }.indexOf(-1) 

floor.foldLeft(0) ((x,y) => { (x + y == -1) {x.indexOf(-1)} } ) 

floor.foldLeft(0) { (x,y) => { if (x + y == -1) { indexOf(-1) } } } 

ここで間違っていることを知りたいのですが、私は本当にその答えのそれ以上の理由を追い求めています。

+0

すべてのソリューションはfoldLeftについて重要なポイントを見逃しています。値 'x'は初期値の型であり、この場合は' 0'であり、関数が返す型はこの型を持つ必要があります。最初の例では、ブール値です。他の2つは意味をなさない。 – pedrofurla

答えて

2

匿名関数(foldLeftへの第2引数は)第一引数と同じ型を返す必要があります。

foldreduce家族は、コレクションを取り、単一の値にそれを減らすために設計されています。ここであなたのために働くつもりはありません。

これはあなたが望むものを得るでしょう。この場合

floor.scanLeft(0)(_+_).indexOf(-1) - 1 // scan collection is 1 element longer 

scanは、対象の要素に照会することができる異なる特性/値を使用して新しいコレクションを生成します。


ですから、本当にfoldLeftを使用する必要性、これをしようとした場合。

floor.zipWithIndex.foldLeft((0,-1)) { 
    case ((s,x),(e,i)) => if (s+e == -1 && x < 0) (0,i) else (s+e, x) 
}._2 

かなり醜いあなたは、現在の合計を持ち歩く必要があるため、s、あなたがどこにいるのインデックス、i、と評価されている現在の要素、e、そしてあなたがあなたの目標を見つけた後、x、あなたは最後にそれを保管して開封してください。._2

結果をscanLeftと比較してください。最終的に- 1の調整が必要であることがわかります。


ここで所望の目標が達成されたときに/場合の早期救済の利点を持っている一つの他のアプローチがあります。

val floorSums:Stream[Int] = Stream.tabulate(floor.length){ idx => 
    floor(idx) + (if (idx>0) floorSums(idx-1) else 0) 
} 

floorSums.indexOf(-1) // 38 
+0

あなたはindexOf(-1)がすべての出現に対して正しく機能していますか?要素-1はコレクションに何度も現れます。 –

+0

巧妙な解決策... – pedrofurla

+0

@MrD、結果のスキャンコレクションに値「-1」が2回表示されます。 'indexOf(-1)'は最初のオカレンスである '39'を返します。 – jwvh

2

操作の途中で救済する必要があるかもしれないこのような問題には、2つのスタイルの解決方法があります(この場合はフォールド)。

一つのスタイルは、(:元プラスインデックスを.zipWithIndexは、要素のペアにすべての要素を回すことに注意してください):ちょうどこの目的のためにあなたが書いdef内部の非局所的なリターンを使用することです

def exceedsTen(xs: List[Int]): Int = { 
    xs.zipWithIndex.foldLeft(0){ (sum, x) => 
    val now = sum + x._1 
    if (now > 10) return x._2 
    else now 
    } 
    -1 
} 

もう1つのスタイルは、完了したことを示すために渡すことができる価値があることです - リストの残りの部分をすべて実際にトラバースしますが、持っていないことを知っているので、何もしませんに。この場合

def overTen(xs: List[Int]): Int = { 
    val pair = 
    xs.foldLeft((0, 0)){ (si, x) => 
     if (si._1 > 10) si 
     else (si._1 + x, si._2 + 1) 
    } 
    if (pair._1 > 10) si._2 else -1 
} 

、実行中の合計を維持し、あなたが探していたものを見つけ指数は少しより多くのスペースを取りますが、あなたは両方の形式を理解してもらった、おそらく少し明確です。

一般に、物事のインデックスを見つけることは、ニッチアプリケーションの一種です。あなたはをしたい何かを見つけて、後でその位置にぶら下がっていない何か。

+0

これはStreamsの役に立つユースケースではありませんか? – pedrofurla

関連する問題