Is there a way to loop through a specific array?
For example, user.org_names returns:
["NEW", "Gold", "HEALTH SPRING"] ["Text Illinois"] ["Star Gold"] ["NEW", "Star Gold"] ["NEW", "Star Gold", "HEALTH SPRING"] ["Star Gold"] ["Star Gold"] ["Text Illinois", "Star Text", "Star Gold"] ["Text Illinois", "HEALTH SPRING"] ["NEW", "Star Gold", "Star Text"]
Now, I want to loop only through the fourth array ["NEW", "Star Gold"].
Is that a possibility in Ruby? I couldn't find such a feature.
You can use the basic array notation [] with the index as argument to get the value:
user.org_names[3] # get the 4th element of the array returned
# returns nil if does not exists
In your case, if you want to loop on the 4th element:
fourth_element = user.org_names[3]
fourth_element.each do |element|
# use element
end if fourth_element.present?
This behaves the same as:
fourth_element = user.org_names[3]
if fourth_element.present?
fourth_element.each do |element|
# use element
end
end
if after the end
1.9.3p489 :006 > [1,2,3].each do |n|
1.9.3p489 :007 > puts n
1.9.3p489 :008?> end if false
=> nil
Basically the same as doing:
[1,2,3].each{ |n| puts n } if false
But using a do/end syntax and multi-line
You can do that this way
user.org_names[3].each do |element|
puts element
end
If this is an array of arrays, maybe you could get the fourth element (user.org_names[3]) of the array and loop through it like this:
<% i = 0 %>
<% user.org_names[3].each do |a| %>
<% a[i] %>
<% i+=1 %>
<% end %>
Related
I got this very confusing array of hashes as an API response.
http://jsfiddle.net/PP9N5/
( the full response is massive. Posting only a part of it but it covers all elements of the response)
How can I get to "airlines".
I tried this
<% #flight["air_search_result"]["onward_solutions"]["solution"].each do|h| %>
<strong><%=h["pricing_summary"]["total_fare"] %></strong> -
<% h["flights"]["flight"]["segments"]["segment"].each do |s| %>
<%= s['airline'] %>
<% end %> <br> <hr>
<% end %>
And I get this error
can't convert String into Integer
I did some modifications like
<%= h["flights"]["flight"]["segments"]["segment"].first["airline"] %>
Error received - can't convert String into Integer
and
<%= h["flights"]["flight"]["segments"]["segment"][0]["airline"] %>
Error received - undefined method '[]' for nil:NilClass
Isnt there a simple way, like I say to find a key "airline" and for that key it returns its value. I stumbled upon this link, though I dont get any error, I also dont get any result.
Thanks.
UPDATE
I did this
<% h["flights"]["flight"]["segments"]["segment"].each do |o,p| %>
<% if o=="airline" %> <%= p %> <% end %>
<% end %> <br> <hr>
<% end %>
I can get few values of airlines where inside segment there is no array.
For eg, i can get where departure_date_time is 2014-07-07T07:10:00, index = 5.
http://jsfiddle.net/PP9N5/1/ (scroll down)
Here is some code you can add which will extract all keys equal the parameter in any Hash within your Hash:
class Hash
def deep_find(query, &block)
flat_map do |key, value|
if key == query
yield value if block_given?
[value]
elsif value.is_a? Hash
value.deep_find(query, &block)
elsif value.is_a? Array
value.select { |i| i.is_a? Hash }.flat_map { |h| h.deep_find(query, &block) }
end
end
end
end
Example:
hash = {"h" => [{ 'x' => [1, 5] }, { 'x' => 2 }, { 'f' => { 'x' => [3, 4] } }], 'x' => 6 }
hash.deep_find('x') { |x| puts "#{x}" }
# [1, 5]
# 2
# [3, 4]
# 6
# => [[1, 5], 2, [3, 4], 6]
it's a tipical problem :D
Replace "=>" for ":" and render.
your_json = {.....}
your_json.gsub("=>", ":")
puts your_json
You can validate a JSON before to work it with http://jsonlint.com/.
when i look at my console after submitting a form i can see like
Parameters: {"authenticity_token"=>"l0dqmb95MydzCWMugWdYt/2bGYyRyDF5ZfOGjrKhjfc=", "project_id"=>"second", "esthour"=>{"nonmodulhours_attributes"=>{"0"=>{"nonmodul_id"=>"61", "nonmodul_est_hours"=>"1"}, "1"=>{"nonmodul_id"=>"62", "nonmodul_est_hours"=>"9"}, "2"=>{"nonmodul_id"=>"63", "nonmodul_est_hours"=>""}}, "modul1hours_attributes"=>{"0"=>{"modul1_est_hours"=>"8", "modul1_id"=>"25"}, "1"=>{"modul1_est_hours"=>"", "modul1_id"=>"26"}**, "2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}**, "ecommerce_est_hours"=>"", "modulhours_attributes"=>{"0"=>{"modul_est_hours"=>"8", "modul_id"=>"53"}, "1"=>{"modul_est_hours"=>"1", "modul_id"=>"54"}, "2"=>{"modul_est_hours"=>"8", "modul_id"=>"55"}}, "cms_est_hours"=>"", "nonmodul1hours_attributes"=>{"0"=>{"nonmodul1_id"=>"25", "nonmodul1_est_hours"=>"2"}, "1"=>{"nonmodul1_id"=>"26", "nonmodul1_est_hours"=>""}, "2"=>{"nonmodul1_id"=>"27", "nonmodul1_est_hours"=>"5"}}, "rfp_id"=>"35"}, "commit"=>"Add Todo", "utf8"=>"✓"}
here how can i arrange the attributes like line
"2"=>{"modul1_est_hours"=>"88", "modul1_id"=>"27"}}
to
"2"=>{ "modul1_id"=>"27","modul1_est_hours"=>"88",}}
**mean modul1_id before modul1_est_hours
form.html.erb**
<% #m1.map(&:id).each do |id|%>
<%= modul1(id) %> <%= f.hidden_field :modul1_id, :value => id %>
<%= f.number_field :modul1_est_hours, :size => 30 %>
</tr>
<% end %>
Edit
def get_issue_attribute_param1(u)
u.each do |key, value|
value.is_a?(Hash) ? get_issue_attribute_param1(value) : update_issue(key,value)
end
end
def update_issue(q,p)
if q.include?("_")
q1 = q.split("_")
q0 = q1[0]
if q1[0].include?("modul") && q1[1] == "id"
$id_map = p
puts $id_map
end
end
end
Here you go(in irb):
a = {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
=> {"modul1_est_hours"=>"88", "modul1_id"=>"27"}
Hash[a.sort{|x,y| y.first <=> x.first }]
=> {"modul1_id"=>"27", "modul1_est_hours"=>"88"}
But, as everybody pointed out. If you could tell what you're trying to do, or what do you want with this? Then maybe what you're looking for maybe little more easy to understand and answer. :)
Edit
Here are the updated methods:
def get_issue_attribute_param1(params)
ids = []
params["esthour"].select{|hour| hour.include?('modul') }.each_pair do |key, value|
ids << update_issue(value)
end unless params["esthour"].nil?
ids # will have array of array like this: [["61", "62", "63"], ["25", "26", "27"], ["53", "54", "55"], ["25", "26", "27"]] for which you can do: `.flatten`
end
def update_issue(id_with_hours)
id_with_hours.values.map{|m| m.select{|v| v.include?('id') } }.map(&:values).flatten
end
Though I am not clear for what purpose you're using $id_map and hence I had to leave that scenario for you to handle. :)
I hope it helps.
I have an array [["Company Name", "Field6"], ["Email", "Field5"]]
And from that array I am creating array of fields with values:
[
[{:label=>"Company Name", :value=>"gfdgfd"}],
[{:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
]
using
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |field|
[
label: field[0],
value: params[field[1]]
]
end
and then I want to pass that labels and values to erb template(something like):
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field.label %>
v: <%= field.value %>
<% end %>
How will be the best way to collect these fields_with_values ? Maybe I should use Object.new
Convert to a hash instead.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
fields_with_values = Hash[*fields.flatten]
# => {"Company Name"=>"Field6", "Email"=>"Field5"}
In your view, parse the hash:
<% fields_with_values.each do |label, value| %>
l: <%= label %>
v: <%= params[value.intern] %>
<% end %>
Note that this will break if your input array is uneven, ie. a key without a value.
EDIT
As mentioned in a comment below (+1), duplicate keys will not work. Fields that have the same label as another field are no good.
fields = [["Company Name", "Field6"], ["Email", "Field5"]]
# first element in array is Label and second is param id
fields_with_values = fields.collect do |label, param_id|
# It looks like there is no need for a nested array here, so just return a Hash
{
label: label,
value: params[param_id]
}
end
#=> [{:label=>"Company Name", :value=>"gfdgfd"}, {:label=>"Email", :value=>"gfdgfd#gfd.pl"}]
It looks like you are trying to use dot syntax to get values out of a Ruby Hash similar to how you would use dot syntax for a JavaScript object (e.g. field.label). Unfortunately this doesn't work for Ruby. I wish it did because it looks very clean. For the Ruby Hash you must use an index, which is a symbol in this case: field[:label]. Your ERB code will look something like this:
# template.erb
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
The easy most basic way would be:
class Foo
attr_accessors :label, :value
def initialize (label, value)
#label = label
#value = value
end
end
fields_with_values = fields.map do |field|
Foo.new(field[0], params[field[1]])
end
from here on you can make it more Ruby way with splat operator or create the objects on the fly, etc. etc.
l:
v:
I would do
fields_with_values = fields.collect do |field|
{label: field[0], value: params[field[1]}
end
And in the view
<% fields_with_values.each do |field| %>
l: <%= field[:label] %>
v: <%= field[:value] %>
<% end %>
However, lets say label is a company and value is an e-mail. If you have a class like
class Company < SomethingOrNothing
attr_accessible :name, email
# methods here
end
You could do
#companies = fields.collect do |field|
Company.new(name: field[0], email: field[1])
end
And then
<% #companies.each do |company| %>
l: <%= comapny.name %>
v: <%= company.email %>
<% end %>
However, most likely creating a new class just for that is over engineering, unless you will use this class over and over in your code.
I have this problem, where I keep on getting
TypeError: can't convert String into Integer
This is where I'm going through this #data object.
here is the #data object
#data = HTTParty.get("")
{
"body"=>{
"predictions"=>{
"direction"=>{
"prediction"=>[
{
"epochTime"=>"1362931090892",
},
{
"epochTime"=>"1362931747892",
},
{
"epochTime"=>"1362932467892",
},
{
"epochTime"=>"1362933187892",
},
{
"epochTime"=>"1362933847892",
}
],
"title"=>"xxxx"
},
"a"=>"xx",
"b"=>"x"
},
"name"=>"some"
}
}
and my code to go through above has been
<% if #data["body"]["predictions"].present? %>
<% #data["body"]["predictions"].each do |p| %>
<%p["direction"].each do |d|%>
<% d["prediction"].each do |k|%>
<h4><%= k["epchoTime.."] %> </h4>
<%end%>
<%end%>
<%end%>
<%end%>
I have no idea how to go through this, I assume this is due to the fact I should access stuff like I do in C++ with name[integer] value, but I would like to use ["name"]. How can I make my code work ?
Thanks for your precious time and consideration.
Here's an example, using Nokogiri, of parsing the raw XML:
require 'nokogiri'
doc = Nokogiri::XML(<<EOT)
<body>
<predictions>
<direction>
<prediction>
<epochTime>1362931090892</epochTime>
<epochTime>1362931747892</epochTime>
<epochTime>1362932467892</epochTime>
<epochTime>1362933187892</epochTime>
<epochTime>1362933847892</epochTime>
</prediction>
<title">xxxx</title>
<a>"xx"</a>
<b>"x"</b>
<name>"some"</name>
</direction>
</predictions>
</body>
EOT
epoch_times = doc.search('epochTime').map(&:text)
Which returns an array of epochTime values:
[
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
Sometimes we need to loop through all prediction blocks containing the epochTime blocks. This will do it:
epoch_times = doc.search('prediction').map{ |predict|
predict.search('epochTime').map(&:text)
}
[
[0] [
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
]
Sometimes you need to find a particular node and grab all the elements of a certain type inside it:
doc = Nokogiri::XML(<<EOT)
<body>
<predictions>
<direction>
<prediction id="1">
<epochTime>1362931090892</epochTime>
<epochTime>1362931747892</epochTime>
<epochTime>1362932467892</epochTime>
<epochTime>1362933187892</epochTime>
<epochTime>1362933847892</epochTime>
</prediction>
<title">xxxx</title>
<a>"xx"</a>
<b>"x"</b>
<name>"some"</name>
</direction>
</predictions>
</body>
EOT
epoch_times = doc.search('prediction[id="1"]').map{ |predict| predict.search('epochTime').map(&:text) }
[
[0] [
[0] "1362931090892",
[1] "1362931747892",
[2] "1362932467892",
[3] "1362933187892",
[4] "1362933847892"
]
]
the Tin Man has a good point about keeping this logic outside the view, and should be a work of a model. Here is a cleaner view though.
<% #data['body']['predictions']['direction']['prediction'].each do |x| %>
<% x.each do |k, v| %>
<h4><%= v %></h4>
<% end %>
<% end %>
Looks like you are ignoring the keys which don't have nested values say title and a , b .
"title"=>"xxxx"
},
"a"=>"xx",
"b"=>"x"
},
Your final code should look like
if #data["body"]["predictions"].present?
#data["body"]["predictions"].each do |p|
p.each do |d|
if d.kind_of? Hash
d.each do |k|
if k.kind_of? Array
k.each do |x|
if x.kind_of? Array
x.each do |y|
if y.kind_of? Hash
puts y["epochTime"]
end
end
end
end
end
end
end
end
end
end
The above code is ugly but you are C++ programmmer , you might like it :P
The whole hash things was getting out of hand as I had constantly detect each one's present and loop through it, so As Tin man suggested, I used XML 'nokogiri' and then used .css method to detect if it existed and looped through it, since original response was in xml.
#doc.css('predictions').each do |predictions_node|
predictions_node.css('direction').each do |direction_node|
direction_node.css('prediction').each do |prediction|
// stuff here
Thanks for your time and consideration.
I have an each statement in a view:
<tr><% #quantity.each do |hash| %>
<td><%= hash.map { |key, value| "Channel: #{key} Quantity: #{value} units" } %>
</td><% end %></tr>
which is rendering on the webpage with square brackets and inverted commas, thus:
["Channel: 1 Quantity: 4675 units"]
["Channel: 2 Quantity: 2864 units"]
The array of hashes that it's looping round is this:
[{2=>2864}, {1=>4675}]
How do I stop the [" from showing up on the page?
Thanks!
map maps a hash into an array. The output is what it should be. Instead of using map, try:
#quantity.each do |hash|
hash.inspect
end
Should help.
Edit in response to your comment:
#quantity.each do |hash|
hash.each do |key, value|
"Key: #{key} Value: #{value}"
end
end