2012-03-13 5 views
1

人を表す多数のレコード(数百万)を処理する必要があります。私は、生年に基づいてパーティションを作成し、各グループを別々に処理したいと考えています。私は、スレッドセーフで並列化できるように、機能的なソリューション(最小/最小限の変更可能なデータ)を作成しようとしています。Seqの変更可能なマップをScalaのIndexedSeqの不変のマップに変換する

私の最初の試みでは、誕生年ごとに一連の人物記録をマッピングするMap[Int, IndexedSeq]を構築するテール再帰関数を作成しました。私は各グループの人々にランダムアクセスをしているので、索引付けされたシーケンスが必要です。ここに私のコードです:

@tailrec 
def loop(people: Seq[Person], 
     map: Map[Int, IndexedSeq[Person]] = Map()): Map[Int, IndexedSeq[Person]] = { 
    if (people.isEmpty) map 
    else { 
    val person = people.head 
    val yearOfBirth = person.yearOfBirth 
    val seq = map.getOrElse(yearOfBirth, IndexedSeq()) 
    loop(people.tail, map + (yearOfBirth -> (seq :+ person))) 
    } 
} 

これは動作しますが、あまり効率的ではありません。私は、非常にローカライズされた少量の可変性を可能にすることで、より良くすることができます。可変変数のすべてがスタック上にある場合、出力はMapが不変である限り、コードはスレッドセーフになります。

私はこれを内部的に変更可能なMap[Int, List[Person]]を構築し、それを戻り値として不変のMap[Int, IndexedSeq[Person]]に効率的に変換して実装したいと考えています。

Listの変更可能なMapを不変のMap[Int, IndexedSeq[Person]]に最も効率的に変換する方法を教えてください。各年の出生グループの人々に特定の順序はないことに注意してください。

+0

副次的な点はおそらく無関係です:あなたが出産時に分割しているため、AFAICTはこのスレッドの外にマップ自体を渡すことはありません。 –

答えて

6

特性のgroupBy機能を使用しないのはなぜですか? (ドキュメントはこちらです:http://www.scala-lang.org/api/current/index.html#scala.collection.Seq

def groupByYearOfBirth(people: Seq[Person]) = people.groupBy(_.yearofBirth) 

編集:私の最初の命題に反して、.mapValues(_.toIndexedSeq)to provide an IndexedSeq`を使用しないでください。ダニエルは以下のコメントの理由を説明します。

+0

私はそれについて知らなかったので私はあなたのテクニックを使用しませんでした。 :-)それは**まさに**私が必要とするように見えます。スカラは偉大ではありませんか?ありがとう。 – Ralph

+0

はい、スカラでは常に同じです。まず、APIを最初に注意深く見てください。ほとんどの場合、必要なものが正確に含まれています。 ;) – Nicolas

+2

Do * NOT *そのように 'mapValues'を使用してください! 'mapValues'の実装はビューのように機能します。つまり、その値にアクセスするたびにその変換が適用されます。 'Seq'と' IndexedSeq'の違いを考えれば、このようにしても何も得られないでしょう。代わりに、通常の 'map'を使用して、新しい' Map'を作成してください。 –

関連する問題