A hash inside an array [closed] - arrays

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I have this hash:
{"id" => [323, 324], info => ["Test Info", "Test Info2"]}
I would like to have a hash inside an array like this:
array = [
[{"id" => "323", info => "Test Info"}],
[{"id" => "324", info => "Test Info2"}]
]
I have duplicate data. I need to use uniq on id and info to get each id only once. Because of that, I need to join them afterwards.

h = {"id" => [323, 324], "info" => ["Test Info", "Test Info2"]}
h.map { |k, v| [k].product v }.transpose.map &:to_h
#⇒ [
# [0] {
# "id" => 323,
# "info" => "Test Info"
# },
# [1] {
# "id" => 324,
# "info" => "Test Info2"
# }
]
If you want to wrap each nested hash into it’s own array, one more action is required:
h.map { |k, v| [k].product v }.transpose.map(&:to_h).map { |e| [e] }
#⇒ [
# [0] [
# [0] {
# "id" => 323,
# "info" => "Test Info"
# }
# ],
# [1] [
# [0] {
# "id" => 324,
# "info" => "Test Info2"
# }
# ]
# ]

You can use this solution (maybe so OP in this case)
h = {"id" => [323, 324], "info" => ["Test Info", "Test Info2"]}
h.values.transpose.map do |a|
[Hash[h.keys.each_with_index.map { |k, i| [k, a[i]] }]]
end
# => [[{"id"=>323, "info"=>"Test Info"}], [{"id"=>324, "info"=>"Test Info2"}]]

This looks like a job for zip which zippers together two arrays:
hash = {
"id" => [323, 324],
"info" => ["Test Info", "Test Info2"]
}
keys = %w[ id info ]
array = hash['id'].zip(hash['info']).map do |id, info|
Hash[keys.zip(pair)]
end
# => [{"id"=>323, "info"=>"Test Info"}, {"id"=>324, "info"=>"Test Info2"}]
The Hash[] method is used to convert an array of form [['a',1],['b',2]] to a hash of form {'a'=>1,'b'=>2}.

Here are a couple more:
h = {"id" => [323, 324], "info" => ["Test Info", "Test Info2"]}
da_keys = h.keys
h.values.transpose.each_with_object([]) { |a,b| b << da_keys.zip(a).to_h }
#=> [{"id"=>323, "info"=>"Test Info"}, {"id"=>324, "info"=>"Test Info2"}]
rolling_keys = h.keys.cycle
h.values.transpose.map {|a| a.each_with_object({}) {|v,g| g.update(rolling_keys.next=>v)}}
#=> [{"id"=>323, "info"=>"Test Info"}, {"id"=>324, "info"=>"Test Info2"}]

You asked for this:
array = [
[{"id" => "323", info => "Test Info"}],
[{"id" => "324", info => "Test Info2"}]
]
But I assume what you really want is just this:
array = [
{"id" => "323", "info" => "Test Info"},
{"id" => "324", "info" => "Test Info2"}
]
Given this:
h = {"id" => [323, 324], "info" => ["Test Info", "Test Info2"]}
You can do this:
h.map { |k,l| l.map { |v| [ k,v ] } }.reduce(&:zip).map(&:to_h)

Related

entering values into an array in react from given 2d array

I want to enter the first value from every array inside a 2d array, I get the 2d array from the server and my intentions are to use it in one of the client pages (as chart data).
Here is the relevant code:
React.useEffect(() => {
fetch("http://localhost:3001/bitcoin")
.then((res) => res.json())
.then((data) => setData(data.message))
.then((dates) => {
//code right here
})
}, []);
Any idea how to implement it?
first method :
you can use for...of like this :
const Arr = [
[ 1,2,3,4],
['one', 'two' , 'three'],
['un' ,'deux', 'trois' ],
]
const ArrOfFirstValues = []
for(key of Arr){
ArrOfFirstValues.push(key[0])
}
console.log(ArrOfFirstValues)
the output is : [ 1, 'one', 'un' ]
Second method :
you can use .map to iterate it :
const Arr = [
[ 1,2,3,4],
['one', 'two' , 'three'],
['un' ,'deux', 'trois' ],
]
console.log(Arr )
const ArrOfFirstValues = Arr.map(arr => arr[0])
console.log(ArrOfFirstValues)
the output will be :
[ 1, 'one', 'un' ]
It's too easy :
const twoDArray = [
["a", "b", "c"],
["A", "B", "C"],
["aa", "bb", "cc"],
["AA", "BB", "CC"] ]
const firstElements = twoDArray.map(item => item[0]);
console.log(firstElements);
// answer: [ 'a', 'A', 'aa', 'AA' ]
Let me know if it is what you exactly need.
Update :
That was the main idea you need and you can implement like this:
React.useEffect(() => {
fetch("http://localhost:3001/bitcoin")
.then(res => res.json())
.then(jsonData => {
// I assume that jsonData is your 2D array
const twoDimensionArr = jsonData ;
setData(twoDimensionArr);
const firstElementsArr = twoDimensionArr.map(item => item[0]);
console.log(firstElementsArr);
})
}, []);

How to insert key/value pair where the key is the value of another pair? Array of hashes Ruby

Here the array of hashes:
array = [
{:ID => "aaa", :phase => "alpha", :quantity => 80},
{:ID => "aaa", :phase => "beta", :quantity => 160}
]
I'm trying to transform the value of :phase into a key and to assign its value taking the value of :quantity, as follow:
array = [
{:ID => "aaa", :"alpha" => 80},
{:ID => "aaa", :"beta" => 160}
]
Thanks!
I would do it like this:
array = [
{:ID => "aaa", :phase => "alpha", :quantity => 80},
{:ID => "aaa", :phase => "beta", :quantity => 160}
]
array.map { |hash| { :ID => hash[:ID], hash[:phase].to_sym => hash[:quantity] } }
#=> [{:ID=>"aaa", :alpha=>80}, {:ID=>"aaa", :beta=>160}]
You can do it like this:
array.map do |hash|
new_key = hash.delete(:phase)
quantity = hash.delete(:quantity)
hash[new_key] = quantity
hash
end

can't figure out array of hashes ruby

I am trying to turn an array of arrays into an array of hashes. Could someone try to explain what I am exactly doing wrong here? The first array within the array of arrays becomes the keys for the hash. I can get the method to return one hash or even three of the same hashes. But I can't get it return each different new hash within the final array.
table_data = [
["first_name", "last_name", "city", "state"],
["Elisabeth", "Gardenar", "Toledo", "OH"],
["Jamaal", "Du", "Sylvania", "OH"],
["Kathlyn", "Lavoie", "Maumee", "OH"]
]
def convert_table(table_array)
hash = {}
final_array = []
headers_array = table_array.shift
table_array.each_index do |x|
i = 0
until i == headers_array.length
hash[headers_array[i]] = table_array[x][i]
final_array << hash
i += 1
end
end
final_array
end
p convert_table(table_data)
#END GOAL
[ { "first_name" => "Elisabeth", "last_name" => "Gardenar", "city" => "Toledo", "state" => "OH" },
{ "first_name" => "Jamaal", "last_name" => "Du", "city" => "Sylvania", "state" => "OH" },
{ "first_name" => "Kathlyn", "last_name" => "Lavoie", "city" => "Maumee", "state" => "OH" }
Pair up keys (in table_data[0] and values (each other row in table_data) using zip, and map them to a hash:
table_data[1..-1].map { |values| Hash[table_data[0].zip(values)] }
EDIT: The part that doesn't work in your case is having one single hash that you keep reusing. When you do final_array << hash, it doesn't add a snapshot of the hash as it is then; it adds a reference to it. Thus, you don't have an array of three hashes, you have an array with three references to the same hash. You could avoid it by doing final_array << hash.clone to actually take a snapshot; or (much simpler) just make a new hash in each iteration of the loop (move hash = {} into the table_array.each_index loop).
As #Amadan has diagnosed your problem, I will suggest a more "Ruby-like" approach.
keys, *data = table_data
#=> [["first_name", "last_name", "city", "state"],
# ["Elisabeth", "Gardenar", "Toledo", "OH"],
# ["Jamaal", "Du", "Sylvania", "OH"],
# ["Kathlyn", "Lavoie", "Maumee", "OH"]
# ]
keys
#=> ["first_name", "last_name", "city", "state"]
data
#=> [["Elisabeth", "Gardenar", "Toledo", "OH"],
# ["Jamaal", "Du", "Sylvania", "OH"],
# ["Kathlyn", "Lavoie", "Maumee", "OH"]
# ]
[keys].product(data).map { |pair| pair.transpose.to_h }
#=> [{"first_name"=>"Elisabeth", "last_name"=>"Gardenar", "city"=>"Toledo",
# "state"=>"OH"},
# {"first_name"=>"Jamaal", "last_name"=>"Du", "city"=>"Sylvania",
# "state"=>"OH"},
# {"first_name"=>"Kathlyn", "last_name"=>"Lavoie", "city"=>"Maumee",
# "state"=>"OH"}
# ]
The steps are as follows.
a = [keys].product(data)
#=> [[["first_name", "last_name", "city", "state"],
# ["Elisabeth", "Gardenar", "Toledo", "OH"]
# ],
# [["first_name", "last_name", "city", "state"],
# ["Jamaal", "Du", "Sylvania", "OH"]],
# [["first_name", "last_name", "city", "state"],
# ["Kathlyn", "Lavoie", "Maumee", "OH"]
# ]
# ]
The first element of a is passed to map, the block variable pair is assigned and the block calculation is performed.
pair = a.first
#=> [["first_name", "last_name", "city", "state"],
# ["Elisabeth", "Gardenar", "Toledo", "OH"]
# ]
b = pair.transpose
#=> [["first_name", "Elisabeth"],
# ["last_name", "Gardenar"],
# ["city", "Toledo"],
# ["state", "OH"]
# ]
g = b.to_h
#=> {"first_name"=>"Elisabeth", "last_name"=>"Gardenar", "city"=>"Toledo",
# "state"=>"OH"}
Therefore, a.first is mapped to g. The remaining calculations are similar.
Your question has been properly answered by #CarySwoveland and #Amadan.
I'd just like to add that your table basically looks like a CSV table with header.
If your table_data does come from a file, you might as well read it directly with CSV :
csv_table = "first_name,last_name,city,state
Elisabeth,Gardenar,Toledo,OH
Jamaal,Du,Sylvania,OH
Kathlyn,Lavoie,Maumee,OH"
require 'csv'
CSV.parse(csv_table, headers: true).each do |row|
p row
end
It outputs
#<CSV::Row "first_name":"Elisabeth" "last_name":"Gardenar" "city":"Toledo" "state":"OH">
#<CSV::Row "first_name":"Jamaal" "last_name":"Du" "city":"Sylvania" "state":"OH">
#<CSV::Row "first_name":"Kathlyn" "last_name":"Lavoie" "city":"Maumee" "state":"OH">
You can work CSV::Row as with an Hash.
If you really want a Hash, you can use row.to_h :
{"first_name"=>"Elisabeth", "last_name"=>"Gardenar", "city"=>"Toledo", "state"=>"OH"}
{"first_name"=>"Jamaal", "last_name"=>"Du", "city"=>"Sylvania", "state"=>"OH"}
{"first_name"=>"Kathlyn", "last_name"=>"Lavoie", "city"=>"Maumee", "state"=>"OH"}

Create JSON from two arrays

I have two arrays say: x=[1,2,3] and y=['a', 'b', 'c']. I want to create a json using x and y arrays in rails console. What is the optimized way to do it.
The desired JSON should looks like this:
{
"obj":
[
{
"key":"a",
"value": 1
},
{
"key":"b",
"value": 2
},
{
"key":"c",
"value": 3
}
]
}
x = [1,2,3] and y = ['a', 'b', 'c']
{obj: y.zip(x).map { |k, v| {key: k, value: v} } }
#⇒ {
# :obj => [
# {
# :key => "a",
# :value => 1
# },
# {
# :key => "b",
# :value => 2
# },
# {
# :key => "c",
# :value => 3
# }
# ]
# }
If you insist on having string keys:
{ 'obj' => y.zip(x).map { |k, v| { 'key' => k, 'value' => v } } }
To get a json out of the hash, just call to_json on it.

Select a value from an array of hashes

From an array of hashes:
response = [
{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label" => "dog", "name"=>"rex", "id" => 550081}
]
is there a way to write something like:
response.name.kitty
to retrieve the hash that contains this value:
{"label"=>"cat", "name"=>"kitty", "id"=>189955}
You can do this -
response.select{|x| x["name"] == "kitty"}.first
Use a Proc
response = [{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label" => "dog", "name"=>"rex", "id" => 550081}]
finder = Proc.new {|k, v| response.find {|r| r[k] == v} }
Then
finder.call('name', 'rex')
# => {"label"=>"dog", "name"=>"rex", "id"=>550081}
finder.call('label', 'cat')
# => {"label"=>"cat", "name"=>"kitty", "id"=>189955}
You can also pass multiple conditions if required like this:
response = [
{"label"=>"cat", "name"=>"kitty", "id"=>189955},
{"label"=>"cat", "name"=>"kitty", "id"=>189956},
{"label"=>"cat", "name"=>"kitty", "id"=>189957},
{"label"=>"cat", "name"=>"meow", "id"=>189957},
{"label" => "dog", "name"=>"rex", "id" => 550081},
{"label" => "dog", "name"=>"tommy", "id" => 550082},
{"label" => "dog", "name"=>"rex", "id" => 550083}
]
> response.select{|h| h["label"] == "cat" && h["name"] == "kitty" && h["id"] == 189955}
=> [{"label"=>"cat", "name"=>"kitty", "id"=>189955}] # returns array of selected hashes
> response.find{|h| h["label"] == "cat" && h["name"] == "kitty" && h["id"] == 189955}
=> {"label"=>"cat", "name"=>"kitty", "id"=>189955} # returns first match element
if you're using Rails - just use .pluck
array_of_hashes = [
{ name: "Kate", city: "Minsk", country: "Belarus", id: 1 },
{ name: "Mike", city: "New York", country: "USA", id: 2 },
{ name: "Aleh", city: "Warsaw", country: "Poland", id: 3},
]
>> array_of_hashes.pluck(:name)
>>
>> [ "Kate", "Mike", "Aleh" ]

Resources