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

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

ただいまの
回答率

88.33%

2つのSeqのオブジェクトリストを特定の列で比較しマージしたい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,052

ts.tubasa

score 123

おはようございます。

下記のソースを見ていいただきたいのですが、aというリストの中のオブジェクトの"name"と
bというリストの中のオブジェクトの"pname"と比較し、一致したら、リストaの一致した後にデータを差し込みたいと考えております。

記述方法がわからないのが、リストbをみて頂きたいのですが、
Shime("C", "mm")をリストaに差し込んだ後、差し込まれたリストaを利用し、
リストbを比較し、Shime("斎藤", "C")をリストaに差し込まなければいけません。

単純に考えて、リストaとリストbを比較した際に、一致したら、リストaに差し込み、
リストbから削除するといったロジックにするのが良いかと思い、いざ実装をしているのですが、
思い通りの結果の記述ができませんでした。

難しく考えているのかもしれませんが、どうしてもわからないため、皆様のお力を
お借りできればと思っております。

  var a = Seq(Shime("A", "○"), Shime("B", "☓"))
  var b = Seq(Shime("伊藤", "A"), Shime("山田", "B"), Shime("C", "mm"), Shime("斎藤", "C"))

  case class Shime(name: String, pname: String)

  // 下記の結果になるようにしたい
  //
  // a =Seq(
  //   Shime("A", "○"),
  //   Shime("伊藤", "A"),
  //   Shime("B", "☓"),
  //   Shime("山田", "B"),
  //   Shime("C", "mm"),
  //   Shime("斎藤", "C")
  // )

大変、お手数をおかけしますが、ご教授よろしくお願いします。


ご指摘をいただきましたので、編集させて頂きます。

仕様があやふやで失礼いたしました。

ご質問いただきました、想定して頂いた内容で認識はあっていると思います。

今回、なぜ、このような投稿をしたかを、記載させて頂きます。

データベースからデータを取得し、指定の並び順、
更新日時でソートしたリストを表示しようと考えております。

単純にデータベース上に、並び順であったり、優先順のフィールドを設けておけば
解決するような内容ですが、データベースから取得したデータの更新頻度が多いため、
すべてのデータに並び順を持たせてしまうと、追加・削除毎に、採番し直す必要があった為、
他の方法を考えておりました。

考えた方法として、並び替えるデータがどのデータの後ろになるのか?を保持したテーブルを用意し、
プログラムで一覧を作成する際に、保持したテーブルを参照しデータの並び替えを行おうと考えております。

// データベースより取得したリスト
list = Seq("あ", "い", "う", "え", "お", "か")

// 並び替え対象リスト
order = Seq(Order("お","あ"), Order("え","お"))

case clase Order(
value: String, // 挿入する値
targetValue:String // ターゲットとなる値
)

// 結果
newlist = Seq("あ", "お", "え", "い", "う", "か")

処理方法としましては、

1.データを取得(A)
A ... リスト
B ... 並び替え対象リスト

2.リスト(A)を分割
分割条件: リスト(A)のデータが、並び替え対象リスト(B)の"挿入する値"と一致、かつ、ターゲットとなる値が、がリスト(A)に含まれている

A` ... 条件が一致せず残ったリスト C ... 条件の一致したリスト

3.条件が一致せず残ったデータ(A)を、forなどで1件づつ処理を行い、並び替え対象のデータと一致した場合、Cのリストからデータを取得し、Aに挿入

と考えておりました。

プログラムを組んでうちに、3の段階時点で、"お"のつぎが"え"とならないのではないかと疑問に思い、今回、質問内容をやりたいことのみを記載し質問してしまいました。

難しく考え過ぎているのかもしれませんが、ご教授いただけると幸いです。

お手数をおかけしますが、よろしくお願い致します。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

回答ではないのですが・・・

ご質問にはやりたいことの例しか述べられておらず「仕様」が述べられていません。いうまでもなく、仕様によってどのようなアルゴリズムを採るべきかは変化します。もし質問者さんが想定している仕様を明示せずその想定と違う前提を置いたアルゴリズムを回答者が回答してしまうと

「いえそういう仕様ではないのです」

といわないといけなくなりますね。ソフトウェアを設計する際に「利用者が正確な要件を言わない」といったことはよくあること(w;)と思いますが、そうした場合「正確な要件を確認する」ところから始めるべきであろうと思います。

例から想像すると以下のような規則であるように思えますが、このような前提をお考えなのかどうか確認したく思いました。

  • 結果の末尾がShima(α,β)であるとき、a,bの残り要素にShima(?,α)はたかだか一つしかない
  • 結果の末尾がShima(α,β)であるとき、a,bの残り要素にShima(?,α)がなければa,bの残り要素の先頭を次の要素とする
  • 結果の最初の要素はa,bの残り要素の中の先頭要素とする

(最初の回答に書いた規則は曖昧だったので訂正しました。失礼しました。)


追記:補足された質問内容に従い考えてみました。結論からいうと最初のご質問にあるようなa, bのリストのうちaのみ用いる方法です。ちょっと分かりにくい論理にも見えるのでもっと明解な方法があるかも知れません。

object Reorder {
  case class Order(val next: String, val prev: String)

  def main(args: Array[String]): Unit = {
    // 並び替え対象リスト
    val list = Seq("あ", "い", "う", "え", "お", "か")
    // 順序制約リスト
    val order = Seq(Order("お","あ"), Order("え","お"))

    // 順序マップを作る(previous -> nextのペア)
    val orderMap = order.map(o ⇒ o.prev → o.next).toMap

    // 与えた引数から順序マップによって決まる固定的な順列を返す
    // マップ内に含まれない場合は単に引数を単一要素とする列を返す
    // (本件の場合"あ"を渡すとSeq("あ", "お", "え")が返ります。
    def makeOrderedSeq(s: String): Seq[String] = orderMap.get(s) match {
      case Some(next) ⇒ s +: makeOrderedSeq(next)
      case NoneSeq(s)
    }

    // 順序マップ(のnext)に出現しないもののみの列へ要素を挿入
    val result = list
                .filter(s ⇒ order.forall(_.next != s))
                .flatMap(makeOrderedSeq(_))
    println(s"result = ${result}")
  }
}

上はあまり処理効率を気にしておらず順序制約のリストの長さが10個やそこらの程度ならよいのですが、それ以上の長さだとmakeOrderedSeqが再帰になっているので危険かも知れません。
再帰を使わないと以下のような不格好なものになってしまいます・・・
Scala使いの方には「ひどいコード」と言われてしまいそうですが orz

def makeOrderedSeq(s: String): Seq[String] = orderMap.get(s) match {
  case Some(next) ⇒
    val b = mutable.Buffer(s)
    var n = next
    do {
      b += n
      n = orderMap.getOrElse(n, null)
    } while (n != null)
    b
  case NoneSeq(s)
}

もっとよい回答があると思いますが自分の程度ではこのくらいの回答が関の山です。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/04/13 13:13

    早速のご回答ありがとうございます。
    本文に質問を加筆させて頂きました。

    ご指摘頂きましたCは、然るべき順番に並んでいる想定でございます。

    キャンセル

  • 2017/04/14 09:49

    ご回答ありがとうございます。

    サンプルを頂き、自分なりに書いてみました。
    再帰の使い方が、わかりやすく、再帰処理を利用して、コーディングすることにしました。

    Scalaに対して勉強不足なので、ご教授頂き、とても勉強になりました。

    ありがとうございました。

    キャンセル

  • 2017/04/14 10:30

    再帰アルゴリズムだと多分orderの件数がそのまま再帰呼び出しのネストの深さになりますのでスタックオーバーフローが起きることのないよう注意しておいた方がよいと思います。

    キャンセル

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

  • ただいまの回答率 88.33%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る