Archer
Archer

Reputation: 1124

Ruby on Rails array group sort by value

I've got an array with with arrays, containing a key and a timestamp.

["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 22:00:51 CEST +02:00],
["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 22:00:32 CEST +02:00],
["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:58:33 CEST +02:00],
["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:58:01 CEST +02:00],
["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:58:51 CEST +02:00],
["3wyadsrrdxtgieyxx_lgka", Sat, 13 May 2017 01:09:01 CEST +02:00],
["y-5he42vlloggjb_whm8jw", Sat, 22 Apr 2017 22:48:31 CEST +02:00],
["oaxej30u9we17onlug4orw", Sun, 23 Apr 2017 01:46:48 CEST +02:00],
["oaxej30u9we17onlug4orw", Sun, 23 Apr 2017 02:06:56 CEST +02:00],
["rqjwg1ka43mvri0dmrdxvg", Sun, 23 Apr 2017 17:23:34 CEST +02:00],
["ok8nq6tg-kor9jglsuhoyw", Tue, 25 Apr 2017 13:02:16 CEST +02:00],
["riwfm0m-0rmbb6e9kyug2g", Sat, 06 May 2017 06:12:27 CEST +02:00],
["riwfm0m-0rmbb6e9kyug2g", Sat, 06 May 2017 06:17:01 CEST +02:00],
["riwfm0m-0rmbb6e9kyug2g", Sat, 06 May 2017 06:18:04 CEST +02:00],
["gbqfn3_d_tritqoey5khjw", Sat, 06 May 2017 14:14:55 CEST +02:00],
["j___x1oap-veh0u1fo_oua", Sun, 07 May 2017 14:22:37 CEST +02:00],
...

I received this list by ActiveRecord.

MyModel.all.pluck(:token, :created_at)

The Model containing some uniq tokens and some duplicates. The duplicates are interesting.

I want to group the timestaps by the key and look for the first and the last timestamp for each key. So I grouped the array as following:

grp = arr.group_by { |key, ts| key}

Now I receive a list like this:

"vwfv8n5obwqmaw8r9fj-yq"=>[
 ["vwfv8n5obwqmaw8r9fj-yq", Thu, 11 May 2017 10:24:42 CEST +02:00]
],
"kacec6ybetpjdzlfgnnxya"=> [
 ["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 22:00:31 CEST +02:00], 
 ["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 22:01:43 CEST +02:00], 
 ["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:58:17 CEST +02:00], 
 ["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:59:05 CEST +02:00], 
 ["kacec6ybetpjdzlfgnnxya", Fri, 12 May 2017 21:59:59 CEST +02:00]
],
...

Is it possible to sort the dates to get the first and the last date easily? Am I too complicated? I think there should be an easier way to handle the raw data.

Upvotes: 0

Views: 1303

Answers (3)

max
max

Reputation: 102250

To get a a hash with the token as the key and the timestamps as values:

# this gives the same MIN and MAX if there is only one created_at in the group
rows = MyModel.group(:token)
   .pluck("token, MIN(created_at), MAX(created_at)")

# loop though rows and create a hash
rows.each_with_object({}) do |(token, *t), hash|
  hash[token] = t.uniq # removes dupes
end

{
 "rqjwg1ka43mvri0dmrdxvg"=>[2017-04-23 15:23:34 UTC],
 "riwfm0m-0rmbb6e9kyug2g"=>[2017-05-06 04:12:27 UTC, 2017-05-06 04:18:04 UTC]
  # ...
}

If you are simply looking for the records which have duplicates you can just use a WHERE clause that counts the records:

MyModel.where("(SELECT COUNT(*) FROM things t WHERE t.token = things.token) > 1")

Upvotes: 1

Md. Farhan Memon
Md. Farhan Memon

Reputation: 6121

try something like this:

MyModel.order(:created_at).pluck(:token, :created_at).group_by { |key, ts| key }.flat_map{ |k, v| { k => [v.first, v.last] } }

Upvotes: 0

gwcodes
gwcodes

Reputation: 5690

You could do this:

# you already have this bit
grp = arr.group_by { |key, ts| key}

# get the minmax values for each group
grp.map { |k, values_array| { k => values_array.minmax } }.reduce Hash.new, :merge

This should yield something that looks like:

{
  "vwfv8n5obwqmaw8r9fj-yq"=>[
    [Thu, 11 May 2017 10:24:42 CEST +02:00, Thu, 11 May 2017 10:24:42 CEST +02:00]
  ],
  "kacec6ybetpjdzlfgnnxya"=> [
    [Fri, 12 May 2017 21:58:17 CEST +02:00, Fri, 12 May 2017 22:01:43 CEST +02:00]
  ],
  ...
}

Upvotes: 0

Related Questions