2011-05-23 9 views
2

私はScalaの新機能ですが、私が読んだことは、私が取り組んでいるプロジェクトに取り組むのに理想的な言語のようです。述語に一致するリストからサブリストを取得

私はこのようになり、非常に大きなCSVファイルを持っている:私は一度にCSVファイルを読み込むと、同じインデックスを持つすべての要素のリストを生成し、一つの指標にしたい

INDEX, CITY, COST 
    7 , London, 500 
    7 , Paris, 200 
    11 , Rome, 300 
    11 , New York, 100 
    11 , Madrid, 7 

を。

7, London, 500 
7, Paris, 200 

と行を含む第二のリスト:私は、行を含むリストを取得したいと思い、上記の例から

11, Rome, 300 
11, New York, 100 
11, Madrid, 7 

それは、CSVファイルを読み込むために非常に簡単です:

val iter = src.getLines().drop(1).map(_.split(",")) //from SO :) 

しかし、私はサブリストを生成するためのきれいな方法を見つけるのに苦労しています。 Scalaを使用してこれを達成するうえで、すばらしい、簡潔な方法があるはずです。私は特に、データがたくさんあるので、データが遅延ロードされるのが好きです。私はこれをどのように達成するかを提案できますか?

すべてのデータはインデックスで整理されています(インデックスは順不同です)。私が扱っているCSVファイルには、ネストされたカンマやエスケープが含まれていません。

答えて

2

Source.getLinesはすでに遅延しています。それは、必要に応じて基礎となるファイルから各行をフェッチするIteratorを返します。イテレータのほとんどの操作でもイテレータが返されるため、次のコードになります。

val iter = src.getLines.tail map {_ split ","} 

値を正しく指定しました。 Iterator[Array[String]]になり、各String配列は必要に応じて生成されます。

データが遅延してロードされていないことを示唆する特定の問題に遭遇しましたか?このイテレータからあなたのサブリストの1を生産するために

UPDATE

、次のことができます。

val id7 = iter filter {_(0) == 7) 

繰り返しますが、これはまだ怠惰になります。

または...あなたができるグループたくさん:

val grouped = iter.toStream groupBy {_(0)} 

残念ながら、これは完全に怠惰ではありません。最後の行は、最初の列に一意の値を持つ可能性があるため、入力からすべての要素を読み込んで、必要な分割数を知る必要があります。 REPLでは、サブストリームを強制することも簡単ですので、あなたは彼らが含まれているものを見ることができます。

val grouped = iter.toStream groupBy {_(0)} mapValues {_.toList} 
+0

申し訳ありませんが、私は問題に遭遇していない、それは私が達成したいコードです。私が理解できないことは、行をインデックスでグループ化する方法です。基本的にArray [Array [String]]は、インデックス列内の同じ値を持つすべての行をグループ化します。 – Peter

2
scala> List(Array(1,"a"),Array(2,"b"),Array(1,"c")).groupBy(_(0)) 
res1: scala.collection.immutable.Map[Any,List[Array[Any]]] = Map(1 -> List(Array(1, a), Array(1, c)), 2 -> List(Array(2, b))) 

だからあなたは何をすべきかの配列内の最初の要素によってグループに.groupBy(_(0))を追加することです。

+0

+1。注文を保存していないが、OPはそれを求めていない。 –

+1

OP * *は遅延ロードを要求しますが、この回答は完全に回避されます –

1

多くのデータがある場合は、どの操作を行うかをさらに注意する必要があります。

Nが異なる取得するために〜N回でそれを読むのは、あなたのファイルには、メモリーにすべてを読み込むことができない、と引き換えに、あなたが(に強制)に喜んでいることをので大きいと仮定してみようサブセット。

まず、必要なサブセットの数を把握する必要があります。ふりをするgetLinesメソッドを持つものを作成しましょう:

val src = new { def getLines() = Iterator("#", "1,a", "2,b", "2,c") } 

ここですべての初期インデックスを見つける必要があります。 splitを使用することもできますが、多くのデータを処理しているため、実際にはすべてを分解する必要はありません。最初のカンマを見つけようとします(ここには必ずカンマがあります)。

val idx = Set() ++ src.getLines().drop(1).map(s => s.substring(0, s.indexOf(','))) 

これでわれわれが探しているものがわかった。 - 多分.toInt.trim.toIntがいくつかで役立つだろう

より多くのものがあり
class OneIndex(index: String) { 
    lazy val data = src.getLines().drop(1).filter(
    s => index == s.substring(0,s.indexOf(',')) 
).toArray 
} 
val everything = idx.map(i => (i,new OneIndex(i))).toMap 

scala> everything("2").data.foreach(println) 
2,b 
2,c 

1がで追加される場合があります。その後、我々は、私たちは、データを遅延ロードするのに役立ちますクラスの助けを借りて、通過とそれを得ますインデックス値を文字列からintに変換します。また、ファイル全体を複数回読み込む必要があるため、遅延ロードを本当に必要としているかどうか疑問に思うかもしれません。しかし、これは少なくとも基本的なフレームワークです。

関連する問題