質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Scala

ScalaはJava仮想マシンで動作を行うオブジェクト指向型プログラミング言語の1つです。静的型付けの関数型言語で、コンパイルエラーの検出に強みがあります。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

Q&A

解決済

2回答

1804閲覧

Scala  任意の値に対して、複数条件でソートできない。

nbki

総合スコア3

Scala

ScalaはJava仮想マシンで動作を行うオブジェクト指向型プログラミング言語の1つです。静的型付けの関数型言語で、コンパイルエラーの検出に強みがあります。

ソート

複数のデータを、順序性に従って並べ替えること。 データ処理を行う際に頻繁に用いられ、多くのアルゴリズムが存在します。速度、容量、複雑さなどに違いがあり、高速性に特化したものにクイックソートがあります。

0グッド

0クリップ

投稿2021/08/16 03:57

Scalaの基礎を学習中です。
任意のリストに対して、優先順位をつけてソートする実装がわかりません。
(条件: 1の場合はid順でソート、 2の場合は身長順でソート、 3の場合は体重順でソート)

例と、求めたい結果
randomの場合は、idでソートし、idが同じの場合は身長でソート、それでも同じ場合は、体重でソート

// 求めたい結果 List(Member(1,170,60), Member(2,170,55), Member(3,180,60))

      random_2の場合は、身長でソートし、同じの場合はidでソート、それでも同じ場合は体重でソート

// 求めたい結果 List(Member(3,180,60), Member(1,170,60), Member(2,170,55))
// メンバークラス定義 case class Member(id: Int, height: Int, weight: Int) // メンバーを生成 val Takahashi = Member(id = 1, height = 170, weight = 60) val Suzuki = Member(id = 2, height = 170, weight = 55) val Nakamura = Member(id = 3, height = 180, weight = 60) // メンバークラスのSeq val members = Seq(Takahashi, Suzuki, Nakamura) val random = Seq(1,2,3) val random_2 = Seq(2,1,3) def (members: Seq[Member], randomKey: Seq[Int]): Seq[Member] = ???

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

keyExtractor

ヒントだけですが、何らかのキー抽出が必要ですね。

Scala

1def keyExtractor(i:Int):Member => Int = i match { 2 case 1 => m => m.id 3 case 2 => m => -m.height 4 case 3 => m => m.weight 5 case _ => m => 0 6}

sortBy

複数キーのソートはタプルを生成する関数(リテラル)を与える。

Scala

1members.sortBy (m => (m.id, ... , ...))

sortByだけでなく、sorted,sortWith を利用することも考えてください。


追記(Stringも含むソート)

属性がStringも含むソートもという要望に答えて、Ordering[Member]を用意します。結論にまとめました。


結論

Ordering[Member]を使う方が汎用性が高いことがわかりました。理由は次のとおり。

  • Memeberの項目のみならず、Memberから導出できるどんな項目をも、ソートキーにすることができる
  • ソートキーの項目と個数を任意に指定できる

Scala

1 case class Member(id:Int, name:String, height:Int, weight:Int) 2 3 def flexSort(members:Seq[Member], randomKey:Seq[Int]): Seq[Member] = { 4 def comparator(id: Int): Ordering[Member] = id match { 5 case 1 => Ordering.by(_.id) 6 case 2 => Ordering.by(_.name) 7 case 3 => Ordering.by(-_.height) 8 case 4 => Ordering.by(_.weight) 9 case _ => Ordering.by(_ => 0) 10 } 11 val actualOrdering = randomKey.map(comparator(_)).reduce((a, o) => Ordering.comparatorToOrdering(a.thenComparing(o))) 12 members.sorted(actualOrdering) 13 } 14 15 16 17 val Yamada = Member(1,"Yamada", 155,60) 18 val Yamada2 = Member(2,"Yamada", 170,63) 19 val Kawai = Member(3,"Kawai", 181,72) 20 val Yamada3 = Member(4,"Yamada", 155,55) 21 val list = Seq(Yamada, Yamada2, Kawai,Yamada3) 22 val randomKey = Seq(2,100,-3,3,4) 23 val result = flexSort(list,randomKey) 24 result.foreach(println(_))

この方法がベストかと問われれば、他にも良い方法があるかもしれない、と思います。

API

scala.math.Ordering
object Ordering
java.util.Comparator

参考

Scala ソート実験
How to sort a list in Scala by two fields?

投稿2021/08/18 07:54

編集2021/08/24 20:39
xebme

総合スコア1090

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbki

2021/08/18 14:02

回答ありがとうございます。 やってみましたが、実装が難しかったため、再度質問させていただきます。 1、MemberクラスのパラメータにStringがある場合のメソッド 2、keyExtactorの戻り値をsortByにどう使っていいかわからない
xebme

2021/08/18 20:37

1. はヒントの対象外です。条件を変えたければ、質問を変更してください。 Member => Ordering[Member] をちらっと考えましたが、やってみないと分かりません。 2. がこの課題の主題ですから、自分で解くか、解こうとしたコードを質問に追記してください。丸投げでないことを証明しましょう。
guest

0

そういう文字列を作って、その文字列でソートすればいいのでは?

scala

1val members = Seq(Takahashi, Suzuki, Nakamura) 2 3// idでソートし、idが同じの場合は身長でソート、それでも同じ場合は、体重でソート 4scala> members.sortBy{x => "%04d %04d %04d".format(x.id, x.height, x.weight)} 5res14: Seq[Member] = List(Member(1,170,60), Member(2,170,55), Member(3,180,60)) 6 7// 身長でソートし、同じの場合はidでソート、それでも同じ場合は体重でソート 8scala> members.sortBy{x => "%04d %04d %04d".format(x.height, x.id, x.weight)} 9res15: Seq[Member] = List(Member(1,170,60), Member(2,170,55), Member(3,180,60))

むむ?

random_2の場合は、身長でソートし、同じの場合はidでソート、それでも同じ場合は体重でソート
// 求めたい結果
List(Member(3,180,60), Member(1,170,60), Member(2,170,55))

「身長でソートし」ではなく、「身長を降順ソートし」かよ。

scala

1scala> members.sortBy{x => "%04d %04d %04d".format(10000-x.height, x.id, x.weight)} 2res4: Seq[Member] = List(Member(3,180,60), Member(1,170,60), Member(2,170,55))

randomの意味役割を理解できていませんでした。そこを理解できたつもりで、追記。

scala

1... 2val random = Seq(1,2,3) 3val random_2 = Seq(2,1,3) 4 5def sss(members: Seq[Member], randomKey: Seq[Int]): Seq[Member] = 6 members.sortBy{ 7 x => 8 randomKey.map{ 9 _ match { 10 case 1 => x.id 11 case 2 => 10000 - x.height 12 case 3 => x.weight 13 } 14 } 15 .map{"%04d".format(_)} 16 .mkString(" ") 17 } 18 19val aa = sss(members, random) 20println(s" keys: ${random}") 21println(s"result: ${aa}") 22 23val bb = sss(members, random_2) 24println(s" keys: ${random_2}") 25println(s"result: ${bb}") 26 27val random_3 = Seq(3,2,1) 28 29val cc = sss(members, random_3) 30println(s" keys: ${random_3}") 31println(s"result: ${cc}") 32 33 34// keys: List(1, 2, 3) 35// result: List(Member(1,170,60), Member(2,170,55), Member(3,180,60)) 36// keys: List(2, 1, 3) 37// result: List(Member(3,180,60), Member(1,170,60), Member(2,170,55)) 38// keys: List(3, 2, 1) 39// result: List(Member(2,170,55), Member(3,180,60), Member(1,170,60))

投稿2021/08/18 04:23

編集2021/08/18 12:57
shiketa

総合スコア4061

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nbki

2021/08/18 13:52

回答ありがとうございます。 説明が悪いのですが、回答いただいたものは、Seq(1,2,3) , Seq(1,3,2)など考えられる全てのパターンを実装しないといけないため、ソートしたいものが増えて、パターンが増えるほど現実的ではないと思います。 rondom, romdom_2のSeqに対して、数字がどんな順番できても、1つのメソッドで意図した返り値になるようなメソッドにしたいです。
shiketa

2021/08/19 03:46

> 数字がどんな順番できても、1つのメソッドで 追記したものは、どんな順番でもいけてるとおもいますけど。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問