Scalaのリストを2つのフィールドでソートする方法は?


101

Scalaのリストを2つのフィールドで並べ替える方法。この例では、lastNameとfirstNameで並べ替えます。

case class Row(var firstName: String, var lastName: String, var city: String)

var rows = List(new Row("Oscar", "Wilde", "London"),
                new Row("Otto",  "Swift", "Berlin"),
                new Row("Carl",  "Swift", "Paris"),
                new Row("Hans",  "Swift", "Dublin"),
                new Row("Hugo",  "Swift", "Sligo"))

rows.sortBy(_.lastName)

私はこのようなことを試します

rows.sortBy(_.lastName + _.firstName)

しかし、それは機能しません。だから私は良い簡単な解決策に興味があります。

回答:


216
rows.sortBy(r => (r.lastName, r.firstName))

4
lastNameで逆ソートを行い、次にfirstNameで自然ソートを行う場合はどうなりますか?
Sachin K

14
@SachinK:クラスOrdering用に独自に作成し、次のようなメソッドでRow使用する必要があります。このようにカスタムを使用することもできます:。sortedrows.sorted(customOrdering)OrderingTuple2rows.sortBy(r => (r.lastName, r.firstName))( Ordering.Tuple2(Ordering.String.reverse, Ordering.String) )
セニア2014年

5
@SachinK:あなたが実装できるcustomOrderingようにOrdering[Row]、手動または使用Ordering.by:このようval customOrdering = Ordering.by((R:行)=>(r.lastName、r.firstName))(Ordering.Tuple2(Ordering.String.reverse、Ordering.String)) `
セニア2014年

1
優れた。または降順で並べ替えるrows.sortBy(r => (-r.field1, -r.field2))
ブレントファウスト

あなたが使用することはできません@BrentFaust -StringOrdering::reverse次のように使用する必要がありますrows.sortBy(r => (r.lastName, r.firstName))(implicitly[Ordering[(String, String)]].reverse)
セニア2017

12
rows.sortBy (row => row.lastName + row.firstName)

あなたの質問のように、マージされた名前でソートしたい場合、または

rows.sortBy (row => (row.lastName, row.firstName))

最初にlastNameでソートする場合は、firstName; 長い名前に関連する(ワイルド、ワイルダー、ワイルダーマン)。

あなたが書くなら

rows.sortBy(_.lastName + _.firstName)

下線が2つある場合、メソッドは2つのパラメーターを予期します。

<console>:14: error: wrong number of parameters; expected = 1
       rows.sortBy (_.lastName + _.firstName)
                               ^

1
この順序は、おそらく名、次に姓の順に並べるのと同じではないでしょう。
Marcin

1
具体的には、姓が
異なる

7

一般に、安定したソートアルゴリズムを使用している場合は、1つのキーでソートしてから、次のキーでソートできます。

rows.sortBy(_.firstName).sortBy(_.lastName)

最終結果はラストネームでソートされ、次に等しい場合はファーストネームでソートされます。


scala sortByが安定したソートを使用していることを確信していますか?そうでなければ、この答えは意味がありません。
om-nom-nom 2012

1
@ om-nom-nom:scala-lang.org/api/current/scala/util/Sorting$.html quickSortは値型に対してのみ定義されているので、はい。
Marcin

1
rows不変のリストでありsortBy、(変更可能なクラスでも)機能するリストを変更するのではなく、新しい値を返します。したがって、2番目の式は、元の並べ替えられていないリストを並べ替えるだけです。
Luigi Plinge

3
Scalaは、sortByメソッドの内部ではjava.util.Arrays.sortを使用します。これは、オブジェクトの配列に対して安定していることを保証します。したがって、はい、このソリューションは正しいです。(これはScala 2.10でチェックされました)
Marcin Pieciukiewicz 2013年

1
これとタプルを作成する単一のsortByのパフォーマンスについて考えるのは興味深いことです。このアプローチでは、明らかにそれらのタプルを作成する必要はありませんが、タプルアプローチでは、姓が一致する場所で姓を比較するだけで済みます。しかし、それは問題ではないと思います-パフォーマンスが重要なコードを書いているなら、sortByを使用すべきではありません!
AmigoNico 2014年

-3

おそらくこれはタプルのリストに対してのみ機能しますが、

scala> var zz = List((1, 0.1), (2, 0.5), (3, 0.6), (4, 0.3), (5, 0.1))
zz: List[(Int, Double)] = List((1,0.1), (2,0.5), (3,0.6), (4,0.3), (5,0.1))

scala> zz.sortBy( x => (-x._2, x._1))
res54: List[(Int, Double)] = List((3,0.6), (2,0.5), (4,0.3), (1,0.1), (5,0.1))

機能し、それを表現する簡単な方法であるように見えます。


しかし、OPがソートする文字列では機能しません。
典型的なポール

この質問には、タプルのリストに限定されない、いくつかの好評の回答がすでにあります。それを投稿する理由は何ですか?
2014年

@honk:以前のソリューションは実際にはタプルのリストでは機能しません(AFAICT)。私がScalaの初心者ではない場合、以前のソリューションをそのような場合に機能するようにモーフィングする方法を理解しているかもしれませんが、今日はそうではありません。私の答えは、他のScala初心者が私がやろうとしていたことと同じことをするのに役立つかもしれないと思いました。
spreinhardt 2014年

@ user3508605:貢献していただけるとありがたいです。ただし、スタックオーバーフローのアイデアは、特定の問題(ここではそうです)に関する質問と、それらの特定の問題(およびそれらのみ)に対処する回答を提供することです。あなたの答えは別の問題の解決策を提供します。したがって、これはそれを投稿するための間違った場所です。あなたの答えが価値があると思うなら、新しい質問をしてください。新しい質問に対応する問題を記述し、そこに回答を投稿してください。最後に、ここで回答を削除することを忘れないでください。ご協力ありがとうございます!
クラクション

@honk:確かに、私は別の質問に私の回答を移動します。そして、私があなたにこの質問への以前の回答(Marcinから)にコメントを追加するように強いることができるなら、それはちょうど間違っているようです。(私はそれを投稿するのに十分な信頼性ポイントがありません。)その答えの例では、最初に1つのキーで並べ替えてから、別のキーでもう一度並べ替え、最初の並べ替えの結果を効果的に排除しています。少なくとも、タプルのリストには含まれています。
spreinhardt 2014年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.