2010-12-27 2 views
5

JavaのようにScala(2.8)を書く程度を減らそうとしています。ここに私が遭遇した問題の単純化があります。あなたは私のソリューションで「より機能的」な改善を提案できますか?スカラ、私のループをより機能的にする

彼らはまず

var outputMap = new mutable.HashMap[Char,Int]() 
var counter = 0 
for(kvp <- inputMap){ 
    val character = kvp._2 
    if(character !='z' && !outputMap.contains(character)){ 
    outputMap += (character -> counter) 
    counter += 1 
    } 
} 

2回目の試行(あまり良くないを試してみてください

に遭遇しているとして、「Z」値を持つ任意のエントリを破棄することによってマップ

val inputMap = mutable.LinkedHashMap(1->'a',2->'a',3->'b',4->'z',5->'c') 

を変換した文字のインデックスを作成します不変のマップと「foreach」を使用)

var outputMap = new immutable.HashMap[Char,Int]() 
var counter = 0 
inputMap.foreach{ 
    case(number,character) => { 
    if(character !='z' && !outputMap.contains(character)){ 
     outputMap2 += (character -> counter) 
     counter += 1 
    } 
    } 
} 

答えて

11

よりよい解決策:あなたは、機能的にこれをやっている場合

inputMap.toList.filter(_._2 != 'z').map(_._2).distinct.zipWithIndex.toMap 
+1

としてそれを呼び出すと思います!すべての要件をコンパクトでわかりやすい方法で満たします。 (個人的には、フィルタリングする前にマップしますが、これはほとんど問題ありません) –

5

まず、あなたは不変のマップを使用する必要があります。

inputMap.filter(_._2 != 'z') 

、最終的には、再マッピングを行うには、あなただけのその意志、zipWithIndexで(しかし、セットなど)の値を使用できます。

その後、何かを取り除くために、あなたはfilterメソッドを使用しますゼロからカウントアップして、マップに戻って変換します。

inputMap.filter(_._2 != 'z').values.toSet.zipWithIndex.toMap 

値の順序は、*とにかく保存するつもりされていないので、おそらく順序が再びまだシャッフルされた可能性があることは重要ではありません。設定された変換で

編集:同様の静脈ではより良い解決策があります。 Arjan'sを参照してください。 Assumption(*)はLinkedHashMapなので間違っています。したがって、Arjanの解決策である順序を維持する必要があります。

3

私はこのような "パイプライン"を作成しますが、これには多くの操作があり、おそらく短縮される可能性があります。これらの2つのList.mapは1つに入れることができますが、私はあなたには一般的な考えがあると思います。

inputMap 
.toList // List((5,c), (1,a), (2,a), (3,b), (4,z)) 
.sorted // List((1,a), (2,a), (3,b), (4,z), (5,c)) 
.filterNot((x) => {x._2 == 'z'}) // List((1,a), (2,a), (3,b), (5,c)) 
.map(_._2) // List(a, a, b, c) 
.zipWithIndex // List((a,0), (a,1), (b,2), (c,3)) 
.map((x)=>{(x._2+1 -> x._1)}) // List((1,a), (2,a), (3,b), (4,c)) 
.toMap // Map((1,a), (2,a), (3,b), (4,c))

これらの操作を実行すると、要素の順序が維持されます。

2

EDIT:私はOP質問を誤読しました。あなたがランレングスエンコーディングをしたいと思っていました。

val values = inputMap.values.filterNot(_ == 'z').toSet.zipWithIndex.toMap 

EDIT 2:コメントで述べたように、秩序を維持することが重要な場合toSeq.distinctまたは類似を使用ここであなたの実際の質問が私の感想です。

val values = inputMap.values.filterNot(_ == 'z').toSeq.distinct.zipWithIndex.toMap 
+0

OPはランレングスエンコーディングを要求しませんでした。問題(またはコード)を再読み込みします。 –

+0

十分に真実です - あまりにも速く編集してください。新しいソリューションは、期待されるように他のすべてのものとよく似ています。乾杯! – Janx

+0

Rexは自分の答えで指摘したように、 'toSet'は要求を満たしていません。なぜなら、それは注文を保存していないからです。 –

-2

私の経験では、マップや機能言語がうまく動作しないことがわかりました。これまでのすべての回答は、地図をリストに変換し、リストをフィルタリングし、リストを地図に戻します。

これは地図が性質上可変データ構造であるためだと思います。リストを構築するときに、新しい要素を追加するときにリストの基底構造が変更されないことと、真のリストの場合、追加が定数O(1)操作であることを考慮してください。マップの場合、マップの内部構造は新しい要素が追加されたときに大きく変化します。負荷率が高くなりすぎて、追加アルゴリズムが地図のサイズを変更したとき。このようにして、関数型言語は一連の値を作成して、新しいキー/値のペアを導入することによる副作用のために地図にポップすることはできません。

しかし、私はまだ、フィルタリング、マッピング、折り返し/縮小マップのサポートが改善されるべきだと思います。マップから始めるので、マップの最大サイズはわかります。新しいマップを作成するのは簡単です。

もしあなたが関数型プログラミングを手に入れたいのであれば、私は地図から始めるには明確なステアリングを推奨します。機能的な言語が設計されたもの(リスト操作)に固執する。

+0

Scalaは非常に素晴らしい不変のマップを提供します。多くのソリューションがリストに変換されているという事実(ただしRexのものはそうではありません)は、マップを含む制限よりも問題の結果です。 OPは元のキーを気にしないように見えるので、入力データ構造もリストである可能性があります。 –

+1

このコメントは問題には答えず、実際には間違っています(たとえば、ツリーのO(log(n)以外のツリーは、更新すると元のままです)。さらに、OPの質問は、本質的にマッピング操作ではないアルゴリズムを適用することを求めている。なぜなら、マップはインデックス(出現順から推測できる)にすぎないからである。もちろん、多くのソリューションではマップを使用していません。 –

+0

うん、私の間違い。私は質問を見るときハッシュマップを考えました。私は、リンクされたハッシュマップ(挿入順に反復)の振る舞いに気づいていなかったと思います。 私は自分の正気を考える。私はこの質問に答えたい。各キーが 'z'でなく、その値がマップに挿入された最後の時間/インデックス( 'z'文字の挿入を除く)であるキー/値マッピングを持つマップを生成する目的の機能です。 – Dunes

9

私は見つけるこのソリューション少し単純arjan'sより:

inputMap.values.filter(_ != 'z').toSeq.distinct.zipWithIndex.toMap 

個々のステップ:

inputMap.values  // Iterable[Char] = MapLike(a, a, b, z, c) 
    .filter(_ != 'z') // Iterable[Char] = List(a, a, b, c) 
    .toSeq.distinct // Seq[Char]  = List(a, b, c) 
    .zipWithIndex  // Seq[(Char, Int)] = List((a,0), (b,1), (c,2)) 
    .toMap    // Map[Char, Int] = Map((a,0), (b,1), (c,2)) 

注あなただけですので、あなたの問題は本質的に、入力としてマップを含みませんキーを破棄します。私はこれをコーディングしていた場合、私はおそらく

def buildIndex[T](s: Seq[T]): Map[T, Int] = s.distinct.zipWithIndex.toMap 

のような関数を記述し、よりよい解決策がいいです

buildIndex(inputMap.values.filter(_ != 'z').toSeq) 
+0

とてもいいです。特に2番目のスニペットのコメントを感謝します。 – Pengin

関連する問題