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

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

ただいまの
回答率

87.49%

配列の中のハッシュのuniq処理

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 1,778

score 16

RailsでTwitter風のSNSアプリを作っているのですが、

1.フォローしているアカウントのツイート
2.自分のツイート
3.フォローしているアカウントがリツイートしたツイート

をタイムラインに表示させるために一度それぞれでActiveRecodeRelationで取得したツイートをハッシュ化し、大元の1つの配列に入れているのですが、

1と3でツイートが重複する事があり、例えば自分がフォローしている二人がそれぞれのツイートをリツイートし合った場合に1にも3にも該当のツイートが格納される事になり、同じツイートが2回3回...と格納されてしまいます。

図で表すと

大元の配列[
-ハッシュ{
--id:1 , body:〇〇}
-ハッシュ{
--id:1 , body:〇〇 retweet:true(リツイートで流れたツイートか否かを判別するキー)}
-ハッシュ{
--id:2 , body:△△}
-ハッシュ{
--id:3 , body:□□}]

簡単に表すとこのような状況なのですが、これをそのままArray.uniqメソッドを使うと、
ハッシュの中の重複しているidの部分だけが削除されて、残りのbodyその他の部分は残ったままです。(ハッシュ自体が消されるわけではない)

理想の挙動としては、idが重複しているハッシュがある場合、retweetではない純粋なツイートのみを残すような書き方をしたいのですが、
いい方法が見つかりません。同じような経験をされている方いましたらご教授願いたいです。

現在のコード

        @user = current_user
        @users = @user.followings
        @following_user_id = []
        @users.each do |following|
            @following_user_id.push(following.id)
        end
        @following_user_id.push(current_user.id)
        @retweet_ids = Retweet.where(user_id: @following_user_id)
        @tweet_array = []
        @tweet_hash = Hash.new{[]}
        @retweet_ids.each do |retweet_id|
            @tweet_hash = Hash.new{[]}
            @tweet_hash["id"]=retweet_id.tweet.id
            @tweet_hash["body"]=retweet_id.tweet.body
            @tweet_hash["user_id"]=retweet_id.tweet.user_id
            @tweet_hash["status"]= 1
            @tweet_hash["status_by"]= retweet_id.user_id
            @tweet_hash["score"]= retweet_id.tweet.score
            @tweet_hash["created_at"]= retweet_id.tweet.created_at
            @tweet_hash["updated_at"]= retweet_id.tweet.updated_at
            @tweet_array.push(@tweet_hash)
        end

        @follow_tweets = Tweet.where(user_id: @following_user_id)

        @follow_tweets.each do |follow_tweet|
            @tweet_hash = Hash.new{[]}
            @tweet_hash["id"]=follow_tweet.id
            @tweet_hash["body"]=follow_tweet.body
            @tweet_hash["user_id"]=follow_tweet.user_id
            @tweet_hash["status"]= 0
            @tweet_hash["score"]= follow_tweet.score
            @tweet_hash["created_at"]= follow_tweet.created_at
            @tweet_hash["updated_at"]= follow_tweet.updated_at
            @tweet_array.push(@tweet_hash)
        end
        @tweets = @tweet_array.sort_by! {|h| h["updated_at"]}.reverse
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

+1

retweetでないものが必ず含まれるのか、含まれない可能性があるのか、で変わります。
必ず含まれるなら
@tweet_array.reject{|tweet_hash| tweet_hash["body"].is_retweet?}

含まれない可能性があるなら
group_by_id = @tweet_array.group_by{|tweet_hash| tweet_hash["id"] }
としますと

{ id1 => [tweet_hash,tweet_hash,tweet_hash],
  id2 => [tweet_hash],
  id3 => [tweet_hash,tweet_hash]
}


の様になりますから、
group_by_id.values.map{|tweet_hashs| この中から一つ選ぶ }
とします

tweet_hash["body"].is_retweet? やこの中から一つ選ぶ部分は見分け方を元に工夫してください

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/03/23 09:21

    ありがとうございます。後者のコードで実装しました。

    group_by_id.values.map{|a| a[0]} でとりあえずは実装しました。この中から一つ選ぶ方法は優先順位をもう少し細かく決めて後ほど細分化したいと思います。

    これは質問とは直接関係ないのですが、この後配列をソートするつもりなのですが、
    @tweets.sort_by! { |a| a[:created_at] }
    @tweets.sort! { |x, y| x[:created_at] <=> y[:created_at] }
    色々この辺りを試しているのですが、どう書いてもデフォルトの順番から全くソートされず困っています。
    自分で考えた原因は[:created_at]のキーからバリューを呼び出せていないかと考えたのですが、カラムやドキュメントなどを見ると、同じやり方で配列の中に組み込まれたハッシュをソートしている記事があったので、原因が突き止められず困っています。
    tweet_hashの中には確実に"created_at"のキーはあります。

    が、書いてる途中に気づいたのですが、ハッシュがシンボルではなく文字列のキーで設定されているので、呼び出せてないのかもしれません。
    キーをシンボルにしてもう一度試してみます。とりあえずご回答ありがとうございました。とても助かりました。

    キャンセル

  • 2020/03/23 09:26

    シンボルに直したらうまくソートする事ができました。
    文字列をキーにするよりやはりシンボルで管理する方がrubyとして綺麗ですし、メリットが多い事を自覚しました。
    重ね重ねありがとうございます。

    キャンセル

  • 2020/03/23 10:19

    ところで @following_user_id ですが
    @following_user_id = @user.followings.map(&:id)
    でとれません?

    キャンセル

  • 2020/03/23 10:29

    確かにここeachで回すの凄い無駄な気がしてました。mapの理解がまだ不十分で、arrayをeachで回す処理をメソッド化したものだと思ってます。
    複雑なメソッドが苦手で逃げているのですが、できる事の幅が広いメソッドなので、もっと勉強しようと思いました!!
    該当の箇所はcurrent_userのidも込みで
    @following_user_id = @user.followings.map(&:id).push(current_user.id)
    のように修正させていただきました!多分コレで問題ない...?と思います。

    なにからなにまでご指摘ありがたいです!!

    キャンセル

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

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

関連した質問

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