vishwas tej
vishwas tej

Reputation: 169

Pick a key-value pair from an array

I have an array that looks like this

[
  "---\n",
  ":date: 2018-07-31\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-01\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-22\n  :estimated_hours: 4.0\n  :remaining_hours: 0.0\n "
]

I want to pick all the values of the key ":date". I read that I can use Enumerable#select, but I'm not sure how to do it. Can anyone help on this?

Upvotes: 0

Views: 124

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110675

arr = ["---\n",
       ":date: 2018-07-31\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
       ":date: 2018-08-01\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
       ":date: 2018-08-22\n  :estimated_hours: 4.0\n  :remaining_hours: 0.0\n "]

arr.join.scan(/:date: (\d{4}-\d{2}-\d{2})/).flatten
  #=> ["2018-07-31", "2018-08-01", "2018-08-22"]

or

arr.join.scan(/(?<=:date: )\d{4}-\d{2}-\d{2}/).flatten
  #=> ["2018-07-31", "2018-08-01", "2018-08-22"]

(?<=:date: ) being a positive lookbehind,

or

arr.join.gsub(/(?<=:date: )\d{4}-\d{2}-\d{2}/).to_a
  #=> ["2018-07-31", "2018-08-01", "2018-08-22"]

This last option looks a bit odd because I am using gsub merely to create an enumerator that generates matches to a regular expression. This is the result when String#gsub has a single argument and no block. In such situations the name"gsub" is misleading, as there is no substitution of strings with other strings. Think of that form of the method being called match_all. I have found many uses for this form of gsub.

Upvotes: 5

engineersmnky
engineersmnky

Reputation: 29318

Since this looks a heck of a lot like YAML (although it needs a little sanitizing) I would go with:

a = [
  "---\n",
  ":date: 2018-07-31\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-01\n  :estimated_hours: 4.0\n  :remaining_hours: 4.0\n ",
  ":date: 2018-08-22\n  :estimated_hours: 4.0\n  :remaining_hours: 0.0\n "
].map(&:rstrip)

require 'yaml'

data = a[1..-1].map {|s| YAML.load(s.gsub("  ", ""))}
#=> [
#  {:date=>#<Date: 2018-07-31 ((2458331j,0s,0n),+0s,2299161j)>, :estimated_hours=>4.0, :remaining_hours=>4.0}, 
#  {:date=>#<Date: 2018-08-01 ((2458332j,0s,0n),+0s,2299161j)>, :estimated_hours=>4.0, :remaining_hours=>4.0}, 
#  {:date=>#<Date: 2018-08-22 ((2458353j,0s,0n),+0s,2299161j)>, :estimated_hours=>4.0, :remaining_hours=>0.0}]

data.map {|h| h[:date] } 
#=> [#<Date: 2018-07-31 ((2458331j,0s,0n),+0s,2299161j)>, 
#     #<Date: 2018-08-01 ((2458332j,0s,0n),+0s,2299161j)>, 
#     #<Date: 2018-08-22 ((2458353j,0s,0n),+0s,2299161j)>]

Upvotes: 1

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121000

One might use String#[] with regular expression argument and positive lookbehind:

input.flat_map { |e| e[/(?<=:date:\s).*/] }.compact
#⇒ ["2018-07-31", "2018-08-01", "2018-08-22"]

Upvotes: 1

Nimish Gupta
Nimish Gupta

Reputation: 3175

Hope this helps

data = ["---\n", ":date: 2018-07-31\n :estimated_hours: 4.0\n :remaining_hours: 4.0\n ", ":date: 2018-08-01\n :estimated_hours: 4.0\n :remaining_hours: 4.0\n ", ":date: 2018-08-22\n :estimated_hours: 4.0\n :remaining_hours: 0.0\n "]

DATE_REGEX = /:date:\s(.*)\n/

dates = data.map do |record|
  record.match(DATE_REGEX)[1] if record.match(REGEX)
end.compact

Upvotes: 0

Related Questions