Converting array to json in Ruby (Puppet, facter) - arrays

I'm writing a fact for Puppet in Ruby. I have an array
array = [[["User", "Username"], ["Date", "16.12.2014"]], [["User1", "Username1"], ["Date1", "17.12.2014"]]]
I want to convert it to json. I tried to convert it to hash first, but doing like this in Linux
array.each do |userarr|
winusers = Hash[userarr.map! { |pair| [pair[0], pair[1]] } ]
end
I get only the this one [["User1", "Username1"], ["Date1", "17.12.2014"]] pair converted. Doing like this:
array.each do |userarr|
winusers = Hash[userarr.map! { |pair| [pair[0], pair[1]] } ]
winusersa << winusers
end
I get an array of hashes. Coverting it to json winusersa.to_json on Linux I get an array of json format text, on Puppet (facter in fact) I get only the first pair converted. Why in Puppet fact it doesn't work? How to convert that array to get all pairs well formated?

Try this one
array.flatten(1).each_slice(2).map(&:to_h)
=> [{"User"=>"Username", "Date"=>"16.12.2014"}, {"User1"=>"Username1", "Date1"=>"17.12.2014"}]
And then, as an hash, you can easily call to_json

You've already got your Array in the form that the ruby Hash#[] method can consume. I think all you need is this:
% pry
[1] pry(main)> require 'json'
[2] pry(main)> a = [[["User", "Username"], ["Date", "16.12.2014"]], [["User1", "Username1"], ["Date1", "17.12.2014"]]]
[3] pry(main)> puts JSON.pretty_generate(a.map { |e| Hash[e] })
[
{
"User": "Username",
"Date": "16.12.2014"
},
{
"User1": "Username1",
"Date1": "17.12.2014"
}
]

Require 'facter' #if you have facter as gem to test locally require 'json'
array = [
[
["User", "Username"],
["Date", "16.12.2014"]
],
[
["User1", "Username1"],
["Date1", "17.12.2014"]
]
]
put JSON.pretty_generate(JSON.parse(array.to_json))

Related

How to create a JSON Array from a two-dimensional array in Ruby

I have a two-dimensional array like this:
[
["01fe237f804a5eff182dcded115c37d3", 0.0140845],
["026e5f1f7f026bf3c763523206aa44bf", 0.03448275],
["04a1c3c79773bd1ecc0372a991adc815", 0.04617604]
]
I'd like to create a hash first, then convert it to JSON, so that the result looks like the following:
[{address: "01fe237f804a5eff182dcded115c37d3", value: 0.0140845},
{address: "026e5f1f7f026bf3c763523206aa44bf", value: 0.03448275},
{address: "04a1c3c79773bd1ecc0372a991adc815", value: 0.04617604}]
Your desired result is still a Ruby hash. To transform it call map on the array and create a hash for each entry:
a = [
["01fe237f804a5eff182dcded115c37d3", 0.0140845],
["026e5f1f7f026bf3c763523206aa44bf", 0.03448275],
["04a1c3c79773bd1ecc0372a991adc815", 0.04617604]
]
a.map{ |e| {address: e[0], value: e[1]} }
This returns the desired result.
If you want to create a JSON string, require json and do the following:
require 'json'
a = [
["01fe237f804a5eff182dcded115c37d3", 0.0140845],
["026e5f1f7f026bf3c763523206aa44bf", 0.03448275],
["04a1c3c79773bd1ecc0372a991adc815", 0.04617604]
]
a.map{|e| {address: e[0], value: e[1]} }.to_json
This will encode the result to the following string:
"[{\"address\":\"01fe237f804a5eff182dcded115c37d3\",\"value\":0.0140845},{\"address\":\"026e5f1f7f026bf3c763523206aa44bf\",\"value\":0.03448275},{\"address\":\"04a1c3c79773bd1ecc0372a991adc815\",\"value\":0.04617604}]"
You can do as below,
require 'json'
keys = [:address, :value]
arr.map { |values| Hash[keys.zip(values)] }.to_json

ruby sorting hashes inside array

I have an array of hashes that I would like to sort based on the :reference values. But some of the elements within the array do not have a :reference key and therefore cannot be sorted. Is there a way to ignore this field and just sort the hash elements that contain this key?
I've tried the following approach but I'm getting an argument error
ArgumentError: comparison of NilClass with String failed
sort_by at org/jruby/RubyEnumerable.java:503
arr1 = [{:reference=> "F123",
:name=> "test4"
},
{
:reference=> "ZA4",
:name=> "test3"
},
{
:reference=> "A43",
:name=> "test2"
},
{
:name=> "test1"
},
{
:name=> "homework1"
}]
arr1 = arr1.sort_by { |hash| hash[:reference] }
puts arr1
The correct output should look like this :
=> arr1= [
{:reference=>"A43", :name=>"test2"},
{:reference=>"F123", :name=>"test4"},
{:reference=>"ZA4", :name=>"test3"},
{:name=> "test1"},
{:name=> "homework1"}
]
You can only sort on values that can be compared, so if you've got values of different types it's best to convert them to the same type first. A simple work-around is to convert to string:
arr1.sort_by { |hash| hash[:reference].to_s }
You can also assign a default:
arr1.sort_by { |hash| hash[:reference] || '' }
Edit: If you want the nil values sorted last:
arr1.sort_by { |hash| [ hash[:reference] ? 0 : 1, hash[:reference].to_s ] }
If you don't mind temporary variables, you could split the array into two arrays, one containing hashes with :reference and the other those without:
with_ref, without_ref = arr1.partition { |h| h[:reference] }
Then sort the first one:
with_ref.sort_by! { |h| h[:reference] }
And finally concatenate both arrays:
arr1 = with_ref + without_ref

Generate from two ruby arrays an appropriate JSON output

I have two simple ruby arrays and a JSON string mapping the elements of the first array to the elements of the second array:
keys = [:key0, :key1, :key2]
values = [:value0, :value1, :value2]
jsonString = {keys[0] => values[0], keys[1] => values[1], keys[2] => values[2]}
Writing this to a file:
file.write(JSON.pretty_generate(jsonString))
results into a nicely printed json object:
{
"key0": "value0",
"key1": "value1",
"key2": "value2"
}
But how can I generate the same output of two much bigger arrays without listing all these elements explicitly?
I just need something like
jsonString = {keys => values}
but this produces a different output:
{
"[:key0, :key1, :key2]":
[
"value0",
"value1",
"value2"
]
}
How can I map the two without looping over both?
array = keys.zip(values)
#=> [[:key0, :value0], [:key1, :value1], [:key2, :value2]]
Array#zip merges elements of self to the corresponding elements of the argument array and you get an array of arrays. This you can convert into a hash ...
hash = array.to_h
# => {:key0=>:value0, :key1=>:value1, :key2=>:value2}
... and the hash you can turn into a json string.
jsonString = JSON.pretty_generate(hash)
puts jsonString
#{
# "key0": "value0",
# "key1": "value1",
# "key2": "value2"
#}
Use Array#zip to make pairs of values and then make hash of them:
keys = [:key0, :key1, :key2]
values = [:value0, :value1, :value2]
Hash[keys.zip values]
# => {:key0=>:value0, :key1=>:value1, :key2=>:value2}

Convert Array of Arrays into JSON

I have an array of arrays that I'd like to convert into json and output within another array. I have the following array:
weekdays = [["Monday",2],["Tuesday",4],["Thursday",5]]
I would like to include this array within a JSON output like so:
json_output = { :results => weekdays.count, :data => weekdays }
Right now I get this, which just doesn't look right as there are not curly brackets around the "data" field...
{
"results": 2,
"data": [
["Monday", 2],
["Tuesday", 4],
["Thursday", 5]
]
}
Any help would be great!
The output is correct. Curly brackets are around hashes, but your data attribute is a nested array.
If you want to convert a nested array into a hash, just call to_h on it:
{ :results => weekdays.count, :data => weekdays.to_h }
Better to convert it to hash manually.
weekdays = [["Monday",2],["Tuesday",4],["Thursday",5]]
hash_weekdays = Hash.new
weekdays.each do |item|
hash_weekdays[item[0]] = item[1]
end
hash_weekdays #=> {"Monday"=>2, "Tuesday"=>4, "Thursday"=>5}

Ruby hash of arrays remove first element from array

I have an array of arrays arr = [["U6342", "2015-01-12", "Account"],other similar arrays]
then i group it by first element
arr.group_by(&:first)
=> {"U6342"=>[["U6342", "2015-01-12", "Account"],other similar arrays]]
But i want to remove first element from all of arrays and get
=> {"U6342"=>[[ "2015-01-12", "Account"],other similar arrays]]
Is it possible?
One might shift a required element inplace.
arr.group_by &:shift
Whether you do not want to modify an original array:
arr.map(&:dup).group_by &:shift
I think some of the other answerers are overthinking it:
arr = [ ["U6342", "2015-01-12", "Account"],
["U1234", "2015-02-12", "Foo"],
["U6342", "2015-03-12", "Bar"],
["U1234", "2015-04-12", "Qux"] ]
arr.group_by(&:shift)
# => { "U6342" => [ [ "2015-01-12", "Account" ],
# [ "2015-03-12", "Bar" ] ],
# "U1234" => [ [ "2015-02-12", "Foo" ],
# [ "2015-04-12", "Qux" ] ]
# }
Array#shift removes the first element from the array and returns it. arr.group_by(&:shift) removes the first element from each element in arr and groups by it.
You can use this code
arr = [["U6342", "2015-01-12", "Account"], ["U6343", "2015-02-12", "Bank"]]
Hash[arr.map{|ar| [ar.first, ar[1..-1]]}]
# => {"U6342"=>["2015-01-12", "Account"], "U6343"=>["2015-02-12", "Bank"]}
or with "modify" the orginal arr variable
Hash[arr.map{|ar| [ar.shift, ar]}]
I hope this helps
You don't have to use group_by to group-by:
arr = [["dog", "named", "Bert"],
["cat", "named", "Boots"],
["dog", "named", "Hank"],
["pig", "named", "Porky"],
["cat", "named", "Tiger"]]
arr.each_with_object(Hash.new { |h,k| h[k]=[] }) { |(f,*a),h| h[f] << a }
# => {"dog"=>[["named", "Bert"], ["named", "Hank"]],
# "cat"=>[["named", "Boots"], ["named", "Tiger"]],
# "pig"=>[["named", "Porky"]]}
Note this doesn't mutate arr.

Resources