11

これが可能かどうかはわかりませんが、次のようなコードがあります。

val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)
val evens = list.filter { e => e % 2 == 0 }

if(someCondition) {
  val result = evens.filter { e => e % 3 == 0 }
} else {
  val result = evens.filter { e => e % 5 == 0 }
}

しかし、すべての要素を2回反復したくないので、「このコレクションで一般的なすべての偶数を選択する」番号を作成し、他の関数を適用して、1回だけ反復する方法はありますか? ?

4

4 に答える 4

27

listなどの遅延コレクションに変換すると、すべてのフィルター操作 (またはその他のものなど) を 1 回のパスでIterator適用できます。map

val list = (1 to 12).toList
val doubleFiltered: List[Int] =
  list.iterator
    .filter(_ % 2 == 0)
    .filter(_ % 3 == 0)
    .toList
println(doubleFiltered)

を使用してコレクションを Iterator に変換すると.iterator、Scala は実行する操作 (ここでは 2 つの s) を追跡しますがfilter、結果が実際にアクセスされる (ここでは への呼び出しを介して.toList) まで待機します。

だから私はあなたのコードを次のように書き直すかもしれません:

val list = (1 to 12).toList
val evens = list.iterator.filter(_ % 2 == 0)

val result = 
  if(someCondition)
    evens.filter(_ % 3 == 0)
  else
    evens.filter(_ % 5 == 0)

result foreach println

正確に何をしたいかによってIterator、 、Stream、またはが必要になる場合がありますView。それらはすべて遅延計算されます (したがって、1 パスの側面が適用されます) が、複数回反復できるかどうか (StreamおよびView)、後でアクセスするために計算された値を保持するかどうか( ) などの点で異なりますStream

これらのさまざまな遅延動作を実際に確認するには、次のコードを実行して、 、、、またはの<OPERATION>いずれかに設定してみてください。toListiteratorviewtoStream

val result =
  (1 to 12).<OPERATION>
    .filter { e => println("filter 1: " + e); e % 2 == 0 }
    .filter { e => println("filter 2: " + e); e % 3 == 0 }
result foreach println
result foreach println

表示される動作は次のとおりです。

  • List(またはその他の非遅延コレクション): コレクションごとfilterに個別の反復が必要です。結果のフィルタリングされたコレクションは、それぞれが表示できるようにメモリに保存されますforeach
  • Iterator: filters と最初の両方foreachが 1 回の反復で実行されます。が消費されたため、 2 番目foreachは何もしません。Iterator結果はメモリに保存されません。
  • View: どちらのforeach呼び出しでも、コレクションに対して独自の単一パスの反復処理が行われ、filters. 結果はメモリに保存されません。
  • Stream: filters と最初の両方foreachが 1 回の反復で実行されます。結果のフィルタリングされたコレクションは、それぞれが表示できるようにメモリに保存されますforeach
于 2012-08-29T17:56:19.480 に答える
8

関数合成を使用できます。someConditionここでは、構成する関数を決定するときに一度だけ呼び出されます。

def modN(n: Int)(xs: List[Int]) = xs filter (_ % n == 0)

val f = modN(2) _ andThen (if (someCondition) modN(3) else modN(5))

val result = f(list)

(これはあなたが望むことをしません-それでもリストを2回トラバースします)

これを行うだけです:

val f: Int => Boolean = if (someCondition) { _ % 3 == 0 } else { _ % 5 == 0 }
val result = list filter (x => x % 2 == 0 && f(x))

または多分もっと良い:

val n = if (someCondition) 3 else 5
val result = list filter (x => x % 2 == 0 && x % n == 0)
于 2012-08-29T18:38:38.810 に答える
2

これはうまくいきませんか:

list.filter{e => e % 2 == 0 && (if (someCondition) e % 3 == 0 else e % 5 == 0)}

また、別の理由で val に名前を付けていない限り、 FYIe % 2 == 0はすべての偶数を提供します。odds

于 2012-08-29T17:59:38.403 に答える
1

フィルターに 2 つの条件を記述するだけです。

val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)

var result = List(0)
val someCondition = true

result = if (someCondition) list.filter { e => e % 2 == 0 && e % 3 == 0 }
         else               list.filter { e => e % 2 == 0 && e % 5 == 0 }
于 2012-08-29T18:00:30.927 に答える