0

I have to check and select the latest one from the array of hashes. The structure is like this:

'histories':[
{
  {
   ...
  },
  'created': "date1",
  'items':[
    {
     'a': "Ready",
     'b': "dfknsknfs",
    },
    {
     'a': "sdfjbsf",
     'b': "hello23",
    }
  ]
},
{
  {
   ...
  },
  'created': "date2",
  'items':[
    {
     'a': "sknfkssd",
     'b': "ksdfjshs",
    },
    {
     'a': "Ready",
     'b': "shdfjsh",
    }
  ]
},
...
]

I have to first find for the value "Ready" and then i have to select the latest "created" date.

My attempt for this is like

ready_item = histories.select { |item| item.items.detect {|f| f.a == "Ready" } }
ready_item

But since the detect is used, it is returning only the first detected value. But i need to get the latest date. What should be the possible solution of it?

Ahmad hamza
  • 1,816
  • 1
  • 23
  • 46

2 Answers2

2
histories.select { |h| 
  h[:items].detect {|f| f[:a] == 'Ready' } 
}.sort_by {|x| x[:created_at] }.last
lx00st
  • 1,566
  • 9
  • 17
  • `sort_by` is proven to be more efficient, but here sorting is absolutely superfluous, though greedy to resources. – Aleksei Matiushkin Apr 29 '15 at 07:42
  • yes, `reduce` looks better here. But it can be sorted in advance for many items searchs – lx00st Apr 29 '15 at 07:48
  • Anyway, consider a best practice to use `sort_by { |x| x[:created_at] }` instead of plain `sort`. Plus `f.a` should be `f[:a]`. – Aleksei Matiushkin Apr 29 '15 at 07:52
  • Sorting might seem superfluous if your main concern is to write *clever* code, but if you focus on writing *clear* code, and avoid premature optimization, it makes a lot of sense. Prefer `sort_by` when your sort requires a method dispatch. It is optimized using a Schwartzian Transform, making it much more efficient. – Drenmi Apr 29 '15 at 08:15
  • Your solution works but i'm confused here. Since detect return first possible find, then how can `sort_by` is working on it.? – Ahmad hamza Apr 29 '15 at 08:57
  • But `select` will be returning the complete `object` of the `detect's` find. How does `sort_by` compares then ? – Ahmad hamza Apr 29 '15 at 09:14
  • i printed the `x[:created]` so it is printing two values. May be it is comparing with other "Ready" having hashes. i guess – Ahmad hamza Apr 29 '15 at 09:19
  • `sort_by` compares histories by :created_at field.. Thats how `sort_by` works – lx00st Apr 29 '15 at 09:19
  • print first `select` output then make `sort_by` on it - may be it will be clearer – lx00st Apr 29 '15 at 09:21
  • when `sort_by` works it does not know any 'Ready'. It just sorts by :created_at field what `select` have returned – lx00st Apr 29 '15 at 09:23
1

I have made the hash more or less rubyish and if I correctly undrestood the requirement, here you go:

hash = { histories:[
  { created: "2014-04-01",
    items:[
        { a: "Ready", b: "NOT to be chosen" },
        { a: "sdfjbsf", b: "hello23" }
  ]},  
  { created: "2015-04-01",
    items:[
        { a: "Ready", b: "to be chosen" },
        { a: "sdfjbsf", b: "hello23" }
  ]},  
  { created: "2014-03-01",
    items:[
        { a: "sknfkssd", b: "ksdfjshs" },  
        { a: "unready", b: "shdfjsh" }   
   ]}
]}

hash[:histories].select do |item|
  item[:items].detect do |item|
    item[:a] == 'Ready' # select ready only
  end 
end.reduce(nil) do |memo, item| # reduce to newest
  memo = item if memo.nil? || 
         Date.parse(memo[:created]) < Date.parse(item[:created])
end

#⇒ {
#  :created => "2015-04-01",
#    :items => [
#    [0] {
#      :a => "Ready",
#      :b => "to be chosen"
#    },
#    [1] {
#      :a => "sdfjbsf",
#      :b => "hello23"
#    }
#  ]
# }
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160