最初の要素を除くすべての要素に同じ手順(関数)を適用して、コレクションを反復(またはマップ)する必要がある状況に遭遇することがあります。最も単純な例は、コレクションの最大要素を見つけることですが、適切な例ではありません。ここでの操作はべき等です。より現実的な例は、部分ごとのテーブルダンプです。最初のリクエストで、列のヘッダーを含むファイルを作成し、それを入力します。
このパターンを実装するための一般的なアプローチ(または最も慣用的な方法)は何ですか?命令型プログラミングと関数型プログラミングの両方のパラダイムに興味があります。
可能な実装のいくつかの変形(cのような擬似コード):
最初(命令型)
funcFirst(collection[0]); //duplicate code if funcFirst is something1 + func() + something2
for (int i = 1; i < collection.size(); i++){
func(collection[i]);
}
2番目(命令)
for (int i = 0; i < collection.size(); i++){
if (i == 0) //too many extra checks
funcFirst(collection[0]);
else
func(collection[i]);
}
3番目(命令)
for (int i = 0; i < collection.size(); i++){
if (i == 0) //too many extra checks
initSomenthing(collection[0]); //double read of collection[0]
func(collection[i]);
}
最初の(機能的)
funcFirst(collection.first()) //duplicate code if funcFirst is something1 + func() + something2
collection.drop(1).map( func )
2番目(機能的)
collection.iterateWithIndex.map (if index == 0 funcFirst else func)
3番目(機能的)
collection.fold (init(collection.first), func) //double read of collection[0]
最初の要素を別の方法でマッピングするために、Scala
def apply[T,X](f: T=>X, g: T=>X, l: Seq[T]): Seq[X] = l match {
case Nil => Nil
case head :: tail => f(head) +: apply(g,g,tail)
}
> apply((x: Int)=> x*x, (x: Int)=> -x, List(5,4,3,2,1))
res1: Seq[Int] = List(25, -4, -3, -2, -1)
リストが空の場合は何もしないという考え方です。それ以外の場合は、リストのヘッドをこのヘッドの関数に置き換えます。ヘッドはf(head)になり、リストの残りの部分は、要素がテールのテールのヘッドにあるかどうかに関係なく、他の関数gを使用してマップされます。リスト。
@jkが指摘したように、適用する再帰呼び出しはマップに置き換えることができます。ただし、私のアプローチはもう少し柔軟性があります(元の質問に答えるのに必要ではありませんでした)。適用する関数を交互に使用できるため(たとえば、奇数要素の場合はf、偶数要素の場合はg)、どちらかを決定できます。関数は、現在の要素の任意の述語に応じて、次の要素(存在する場合)に適用する必要があります。
リストをスカラー値に分割して個別に処理し、残りを処理するだけです。
val first = list.head
val rest = list.tail
val firstResult = firstFunc(first)
val restResult = rest.map(restFunc)