I am trying to compare the names of the element at the current index and the previous index for each element to determine if they are the same name so I don't print out the name twice.
Unfortunately, trying to access the array element using array[i] doesn't work, but if I hard-code an index or just print out the index, it works fine so I'm not sure where it's messing up.
I need to be able to access the previous element though so I can't use other loops so only suggest something where I can access the previous element in the array.
<% for i in 1..count %>
<% if array[i].count > 1 %>
<% if array[i-1].name == array[i].name %>
<%= array[i].name %>
<%= array[7].name %>
<%= i %>
<% end %>
<% end %>
Does anyone know the correct way to access an element in an array?
This should do it if your list is sorted and all you care about is printing names:
<% array.map(&:name).uniq.each do |name| %>
<%= name %>
<% end %>
More generally, you can do it like this:
array.each_with_index do |el, i|
prev_el = array[i-1] #will be nil for the first element
next_el = array[i+1] #will be nil for the last element
if prev_el && el.name == prev_el.name
#name same as previous
end
if next_el && el.name == next_el.name
#name same as next
end
end
You should avoid index-based array access for loops, not because they don't work but because there are much nicer and more readable ways of looping through arrays in Ruby.
You can keep in mind that you are using Ruby, and the motto of Ruby is "Do More in Less Work".
You can use uniq to filter out all similar elements, then iterate through them to do whatever you want to do. uniq works like this:
a = [ "a", "a", "b", "b", "c" ]
a.uniq # => ["a", "b", "c"]
This should do it all what you tried to do:
<% array.uniq.each do |obj| %>
<%= obj.name %>
<% end %>
Just thought of another way of doing this:
grouped = array.group_by(&:name)
Now you have a hash where each key is a unique name and the corresponding value is all the array elements with that name. So next you can do stuff like
#list of names in alphabetical order
grouped.keys.sort
#get one element for each unique name
grouped.map{|name,els| els.first}
#print out how many you have for each name
grouped.each{|name, els| puts "#{name.inspect} => #{els.size} elements"};false
Related
I feel like this is such an easy question
<% #state.cities.each do |city| %>
<%= city.id %>
<% end %>
puts the ids as follows:
1
2
3 etc...
How do I turn the iteration into an array?
so it outputs as follows:
[1,2,3,4,etc...]
There is a method that does just that!
What you are looking for is the map method.
Creates a new array containing the values returned by the block.
http://apidock.com/ruby/Array/map
The documentation states, creates an array containing the values returned by a block.
#state.map do |state|
state.id
end
=> [1,2,3,...]
Which is the same as:
#state.map(&:id)
=> [1,2,3,...]
But uses the Ruby Enumerable shorthand.
#state.map(&:id) would give you the same result!
You can use map:
<%= #state.map(&:id) %>
I have this code in controller:
array = ["asd", "asd", "asd"]
#print = array.each do |i|
puts "Random text #{i}"
end
And now I want to print it in some pages view like show.html.erb:
<%= #print >
And I get this: ["asd", "asd", "asd"] But In controller I sayd to puts each object in array, but it is not doing it?
The puts method is for printing a string to the console. If you wanted to set each of the values of the array to a certain value in order to print it out later, you should use #map.
array = ['asd', 'asd', 'asd']
#print = array.map { |i| "Random text #{i}" }
Now, in your corresponding view, you should add:
<% #print.each do |val| %>
<%= val %>
<% end %>
puts prints to the stdout (standard output) that, in the majority of cases, corresponds to the console where you started the Rails server.
Check the console and you will find, in the middle of the request logs, also the result of the puts statement.
A better way to print out something from the console is to use the Rails logger, especially if you want such output to be logged in the logs in production.
Rails.logger.info "message"
Assuming it's just for debugging purpose, then it's fine to use puts (or p).
You should be doing the looping in your view. This helps maintain the separation between your application logic and your view code.
Controller
#array = ["asd", "asd", "asd"]
View
<% #array.each do |i|
<%= i %> # No need to use the puts method here
<% end %>
it seems that the variable #print is the array. The controller is run once per load of the page and then will output its contents at the end to the view. Plus, "puts" is for printing a string to the console. You should put the loop in question in the view like this:
<% #array.each do |i| %>
<%= i #>
<% end %>
I'm using Rails 3.0 and the acts_as_taggable_on gem. I have a Candy model and candies can have multiple tags for flavors. Let's say
Candy1.tags #['apple', 'orange']
Candy2.tags #['orange', 'banana']
Candy3.tags #['apple', 'kiwi']
I want a list of tags with associated candies below them, like so:
Apple
Candy1
Candy3
Orange
Candy1
Candy2
...etc.
I've tried
Candy.all.group_by{ |candy| candy.tags }
but that treats the array of tags as a single entity, returning something like this:
['apple', 'orange']
Candy1
['orange', 'banana']
Candy2
Lacking a group_by_each method, whats the best way to accomplish this? Another Stack Overflow question explains how to do this in memory with simple hashes, but I wonder if there's a more database-oriented way to do it with ActiveRecord associations.
You can iterate over the candies and store them on a hash base on the tag:
grouped = {}
Candy.all.each do |candy|
candy.tags.each do |tag|
grouped[tag] ||= []
grouped[tag] << candy
end
end
At the end you will get:
{'apple' => [candy1, candy2], 'orange' => [] ...}
Hope this helps you
candies = Candy.all.inject({}) do |memo, candy|
candy.tags.each do |tag|
memo[tag] ||= []
memo[tag] << candy
memo
end
end
Now candies is a hash like this:
{
'apple' => [Candy1, Candy3],
'orange' => [Candy1, Candy2],
...
}
Which you can iterate over nicely:
candies.each do |key, value|
puts "Candy tag: #{key}"
value.each do |candy|
puts " * #{candy}"
end
end
In rails api documentation that group_by is for collecting enumerable. I think you need to try a more classic array iterator like the following since you've strings data
in views/candy/index.html.erb
<% #candys.each do |candy| %>
<%= candy.name %>
<% end %>
<%for tag in candy.tags %>
<li> <%= tag.name(or flavor %> </li> #tag.name_attribute
<% end %>
<% end %>
Let me know if it works
I have hash(Hash.from_xml) which looks like this (from inspect):
{
"FileName"=>"hofplayers.xml",
"Version"=>"1.0",
"UserID"=>"3955847",
"FetchedDate"=>"2011-08-16 00:41:02",
"PlayerList"=>{
"Player"=>{
"PlayerId"=>"92121587",
"FirstName"=>"Gennady",
"NickName"=>nil,
"LastName"=>"Buzykin",
"Age"=>"45",
"NextBirthday"=>"2011-09-24 22:10:00",
"ArrivalDate"=>"2008-03-08 16:37:00",
"ExpertType"=>"15",
"HofDate"=>"2010-01-23 16:10:00",
"HofAge"=>"40"
}
}
}
Then I'm iterating with each as there can be more then one player:
<% #hof['PlayerList']['Player'].each do |player| %>
<%= player['NickName']%>
<% end %>
And it fails with TypeError: can't convert String into Integer. But it works like I want when there is more than one player. The problem seems to be that when there is single player each makes arrays instead of hash, player.inspect gives:
["PlayerId", "92121587"]
["FirstName", "Gennady"]
["NickName", nil]
["LastName", "Buzykin"]
["Age", "45"]
["NextBirthday", "2011-09-24 22:10:00"]
["ArrivalDate", "2008-03-08 16:37:00"]
["ExpertType", "15"]
["HofDate", "2010-01-23 16:10:00"]
["HofAge", "40"]
Instead of
{
"PlayerId"=>"25787535",
"FirstName"=>"Rico",
"NickName"=>nil,
"LastName"=>"van Oostveen",
"Age"=>"42",
"NextBirthday"=>"2011-10-23 22:18:00",
"ArrivalDate"=>"2006-02-11 18:43:00",
"ExpertType"=>"2",
"HofDate"=>"2010-04-25 22:01:00",
"HofAge"=>"38"
}
So what I'm doing wrong?
When you do each on a Hash, you get a list of key/value pairs, then you try to index those pairs with a string and that gives you your error. There's not much you can do to change what from_xml does but you can work around it.
You could patch the Hash in your controller:
if(#hof['PlayerList']['Player'].is_a?(Hash))
#hof['PlayerList']['Player'] = [ #hof['PlayerList']['Player'] ]
end
# or
if(!#hof['PlayerList']['Player'].is_a?(Array))
#hof['PlayerList']['Player'] = [ #hof['PlayerList']['Player'] ]
end
If you don't have what you're expecting, you'd just make it an array with one element; which test you choose depends on what sorts of things you're expecting to get from from_xml but I'd lean towards the "not array" check since that exactly matches what you're trying to do.
Or you could try sorting it out in your view:
<% [ #hof['PlayerList']['Player'] ].flatten(1).each do |player| %>
That basically wraps whatever you have in an array and then flattens it one level, the flatten(1) call is needed in case you already have an array. If you start off with an array then the [ ].flatten(1) is a no-op (the flatten call will undo what [] does) that won't have any noticeable effect other than a bit of wasted CPU time; if you start with a hash, then [ ... ] will turn it into an array and flatten won't do anything (but waste a bit of CPU).
one thing that comes to mind is that this:
<% #hof['PlayerList']['Player'].each do |player| %>
<%= player['NickName']%>
<% end %>
does not loop through the players. It loops through the name/value pairs of the 'Player' hash. EDIT. By this I mean that it will loop through key1, value1, key2, value2, key3,...etc. One for each iteration of the loop...
I would think you'd want something like this:
<% #hof['PlayerList'].each_pair do |player, player_data| %>
<%= player_data['NickName']%>
<% end %>
I'm new to rails, so forgive me if there is an easy answer. I'm trying to implement an "Alphabet Index" for a table in rails. I want to be able to click on a letter and have the table refresh - containing only the data on which the first letter of the last_name column matches the letter clicked.
My first thought was to generate an array of letter from the database
#visitor_array = []
#v = Visitor.all
#v.each do |visitor|
#visitor_array << visitor.last_name[0,1]
end
#visitor_array.sort!
#visitor_array.uniq!
This code gives me an array which has one of each of the first letters. I used this as my "alphabet". On my view I have the following code
<% #visitor_array.each do |visitor| %>
<%= link_to visitor, alphasort(visitor) %>
<% end %>
The thought here is to run a helper function when the letter is clicked. But here is where I'm stuck.
UPDATE:
Okay, thanks to the comments below, I was able to figure it out. In case anyone else was wondering, this is how it was accomplished.
CONTROLLER
# Create array consisting of the first letter of every visitor's last name
#visitor_array = []
#v = Visitor.all
#v.each do |visitor|
#visitor_array << visitor.last_name[0,1]
end
#Sort array alphabetically in ASC order
#visitor_array.sort!
#Remove duplicate elements
#visitor_array.uniq!
if (params[:letter] != nil)
#visitors = Visitor.order("last_name ASC").where("last_name like ?", params[:letter] +"%" )
else
#visitors = Visitor.order("last_name ASC")
end
VIEW
<% #visitor_array.each do |letter| %>
<%= link_to letter, :controller => "visitors" , :letter => letter %>
<% end %>
Use this to get the list of results for a specific letter:
visitors = Visitor.order("last_name ASC").where("last_name like '?'", letter)
Then on your view:
<% #visitor_array.each do |visitor| %>
<%= link_to visitor(visitor) %>
<% end %>
The syntax might be slightly off but the fundamental idea is there.
I'm not entirely sure what you mean by the last line though...