Convert string representation of nested array to Array - ruby-on-rails

I have a string representation of array:
val1 = "[[\":one\", \":two\"], [\":four\", \":one\"]]"
What is the best way to convert it into:
val2 = [[:one,:two], [:four, :one]]
The dimension of array could be 25 x 25.

Use JSON.parse:
require 'json'
val2 = JSON.parse val1
# => [[":one", ":two"], [":four", ":one"]]
or you can convert them to symbols like this:
val2.map{|a,b| [a.sub(/^:/,'').to_sym, b.sub(/^:/,'').to_sym]}
# => [[:one, :two], [:four, :one]]

You can use YAML.load:
require 'yaml'
YAML.load(val1.delete ':').map{|x| x.map(&:to_sym)}
# => [[:one, :two], [:four, :one]]
Demonstration
And I guess I should be ready for downvotes, but you can use eval:
eval(val1).map{|x| x.map(&method(:eval))}
# => [[:one, :two], [:four, :one]]
Demonstration

eval val1.tr('"','') #=> [[:one, :two], [:four, :one]]

eval val1.gsub '"','' #=> [[:one,:two], [:four, :one]]

val1 = "[[\":one\", \":two\"], [\":four\", \":one\"]]"
puts val1.unpack('ZZ')
Descrition:
'unpack' decodes the string (which may contain binary data). According to the format string, it is returning an array of each value extracted. In the above code, Z stands for null terminated string.

Related

how to convert the given string to array in rails

I have the following Strings. I want them to convert into Arrays like below in rails
"[\"Winter\", \"Summer\", \"Spring\"]" to ["Winter", "Summer", "Spring"]
"[\"IELTS\", \"GRE\", \"PTE\", \"SAT\"]" to ["IELTS", "GRE", "PTE", "SAT"]
How can i convert these
You can do it with JSON.
require 'json'
string = "[\"Winter\", \"Summer\", \"Spring\"]"
JSON.parse(string)
=> ["Winter", "Summer", "Spring"]
just alternate solution (not safe) :
> string = "[\"Winter\", \"Summer\", \"Spring\"]"
> eval(string)
#=> ["Winter", "Summer", "Spring"]
Note: better option to parse with JSON

Ruby - how to use array with Date.strptime

If I try to convert single String to date it works.
require 'date'
a=String.new
a='20171023'
puts b=Date.strptime(a,'%Y%m%d')
puts b.yday()
How can I make it work with an array? I tried this way.
require 'date'
a=[20160106, 20132018, 20011221]
b=a.each{|a| Date.strptime(a, '%Y%m%d').yday()}
puts b
You need to pass a string, instead an integer as you're doing now:
a = ['20160106', '20130218', '20011221']
If you want to store the result of each operation in b, then you can use map instead each:
b = a.map { |date| Date.strptime(date, '%Y%m%d') }
Your second date is invalid, I guess is 20130218.
require 'date'
a = %w[20160106 20130218 20011221]
b = a.map { |date| Date.strptime(date, '%Y%m%d').yday }
p b # [6, 49, 355]
%w[ ... ] is an array of strings, where you avoid using quotes and commas.
When you don't need to pass arguments to a method call, you can avoid parenthesis.
require 'date'
a = [20160106, 20131018, 20011221]
a.map { |n| (Date.parse n.to_s).yday }
NB the array is different from the OP's, I assume he made a typo of some sort as the second number-date was invalid.

New DateTime instead of String in ruby

I've got some issue with DateTime in Ruby
I've got line which looks like this (it's in .txt file)
DateTime.new(1979,1,1) DateTime.new(2012,3,29)
And my function to get this looks like this
def split_line
array = line.split(' ')
#date_of_birth = array[0]
#date_of_death = array[1]
end
But #date_of_birth and #date_of_death class are String. How can I get them as DateTime?
Assuming your string is in the correct format, then you're probably looking for:
#date_of_birth = array[0].to_datetime
#date_of_death = array[1].to_datetime
See here for more info:
https://apidock.com/rails/String/to_datetime
This:
DateTime.new(1979,1,1) DateTime.new(2012,3,29)
Is not code. What do you expect that to do?
If you want two DateTimes as a space-separated string, do something like:
"#{DateTime.new(1979,1,1)} #{DateTime.new(2012,3,29)}"
When you have something like #{...} inside a set of double quotation marks (they must be double, not single quotation marks), it's called string interpolation. Learn it. Love it. Live it.
But, for the life of me, I don't know why you wouldn't do:
[DateTime.new(1979,1,1), DateTime.new(2012,3,29)]
Which gives you an array, so no split needed. Just:
def split_line
#date_of_birth = array[0]
#date_of_death = array[1]
end
If you want DateTime values, grab the numbers and create them:
require 'date'
'DateTime.new(1979,1,1) DateTime.new(2012,3,29)'.split.map { |s|
DateTime.new(*s.scan(/\d+/).map(&:to_i) )
}
# => [#<DateTime: 1979-01-01T00:00:00+00:00 ((2443875j,0s,0n),+0s,2299161j)>,
# #<DateTime: 2012-03-29T00:00:00+00:00 ((2456016j,0s,0n),+0s,2299161j)>]
The values aren't DateTime though, they're Dates:
'DateTime.new(1979,1,1) DateTime.new(2012,3,29)'.split.map { |s|
Date.new(*s.scan(/\d+/).map(&:to_i) )
}
# => [#<Date: 1979-01-01 ((2443875j,0s,0n),+0s,2299161j)>,
# #<Date: 2012-03-29 ((2456016j,0s,0n),+0s,2299161j)>]
Breaking it down:
'DateTime.new(1979,1,1) DateTime.new(2012,3,29)'.split # => ["DateTime.new(1979,1,1)", "DateTime.new(2012,3,29)"]
.map { |s|
Date.new(
*s.scan(/\d+/) # => ["1979", "1", "1"], ["2012", "3", "29"]
.map(&:to_i) # => [1979, 1, 1], [2012, 3, 29]
)
}
# => [#<Date: 1979-01-01 ((2443875j,0s,0n),+0s,2299161j)>,
# #<Date: 2012-03-29 ((2456016j,0s,0n),+0s,2299161j)>]
* (AKA "splat"), used like this, explodes an array into its elements, which is useful when you have an array but the method only takes separate parameters.
The bigger question is why you're getting values like that in a text file.

map array with condition

I have array like
strings = ["by_product[]=1", "by_product[]=2", "page=1", "per_page=10", "select[]=current", "select[]=requested", "select[]=original"]
which is array of params from request
Then there is code that generates hash from array
arrays = strings.map do |segment|
k,v = segment.split("=")
[k, v && CGI.unescape(v)]
Hash[arrays]
CUrrent output -
"by_product[]": "2",
"page":"1",
"per_page":"10",
"select[]":"original"
Expected output -
"by_product[]":"1, 2",
"page":"1",
"per_page":"10",
"select[]":"current, requested, original"
The problem is - after split method there are few by_product[] and the last one just overrides any other params, so in result instead of hash with array as value of these params im getting only last one. And i'm not sure how to fix it. Any ideas? Or at least algorithms
So try this:
hash = {}
arrays = strings.map do |segment|
k,v = segment.split("=")
hash[k]||=[]
hash[k] << v
end
output is
1.9.3-p547 :025 > hash
=> {"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
or if you want just strings do
arrays = strings.map do |segment|
k,v = segment.split("=")
hash[k].nil? ? hash[k] = v : hash[k] << ", " + v
end
Don't reinvent the wheel, CGI and Rack can already handle query strings.
Assuming your strings array comes from a single query string:
query = "by_product[]=1&by_product[]=2&page=1&per_page=10&select[]=current&select[]=requested&select[]=original"
you can use CGI::parse: (all values as arrays)
require 'cgi'
CGI.parse(query)
#=> {"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
or Rack::Utils.parse_query: (arrays where needed)
require 'rack'
Rack::Utils.parse_nested_query(query)
# => {"by_product[]"=>["1", "2"], "page"=>"1", "per_page"=>"10", "select[]"=>["current", "requested", "original"]}
or Rack::Utils.parse_nested_query: (values without [] suffix)
require 'rack'
Rack::Utils.parse_nested_query(query)
# => {"by_product"=>["1", "2"], "page"=>"1", "per_page"=>"10", "select"=>["current", "requested", "original"]}
And if these are parameters for a Rails controller, you can just use params.
this will also work :
strings.inject({}){ |hash, string|
key, value = string.split('=');
hash[key] = (hash[key]|| []) << value;
hash;
}
output :
{"by_product[]"=>["1", "2"], "page"=>["1"], "per_page"=>["10"], "select[]"=>["current", "requested", "original"]}
As simple as that
array.map { |record| record*3 if condition }
record*3 is the resultant operation you wanna do to the array while mapping

Ruby mixed array to nested hash

I have a Ruby array whose elements alternate between Strings and Hashes. For example-
["1234", Hash#1, "5678", Hash#2]
I would like to create a nested hash structure from this. So,
hash["1234"]["key in hash#1"] = value
hash["5678"]["key in hash#2"] = value
Does anyone have/now a nice way of doing this? Thank you.
Simply use
hsh = Hash[*arr] #suppose arr is the array you have
It will slice 2 at a time and convert into hash.
I don't think there is a method on array to do this directly. The following code works and is quite easy to read.
hsh = {}
ary.each_slice(2) do |a, b|
hsh[a] = b
end
# Now `hsh` is as you want it to be
Guessing at what you want, since "key in hash#1" is not clear at all, nor have you defined what hash or value should be:
value = 42
h1 = {a:1}
h2 = {b:2}
a = ["1234",h1,"5678",h2]
a.each_slice(2).each{ |str,h| h[str] = value }
p h1, #=> {:a=>1, "1234"=>42}
h2 #=> {:b=>2, "5678"=>42}
Alternatively, perhaps you mean this:
h1 = {a:1}
h2 = {b:2}
a = ["1234",h1,"5678",h2]
hash = Hash[ a.each_slice(2).to_a ]
p hash #=> {"1234"=>{:a=>1}, "5678"=>{:b=>2}}
p hash["1234"][:a] #=> 1
let's guess, using facets just for fun:
require 'facets'
xs = ["1234", {:a => 1, :b => 2}, "5678", {:c => 3}]
xs.each_slice(2).mash.to_h
#=> {"1234"=>{:a=>1, :b=>2}, "5678"=>{:c=>3}}

Resources