This is my first time posting a question on this site; be gentle, please. This isn't homework. I'll try to be as concise as possible.
I have a table with 5 keyword columns, a date column, and a user ID column for identifying what user added that specific row of data. My goal is to print and count the number of matched keywords from a row iff:
1) Another row(s) contains those keywords AND has the same date.
2) The user ID for each row is unique.
For example:
Row1=> keyword1:(K1) keyword2:(K2) keyword3:(K3) keyword4:(K4) keyword5:(K5) date:(D1) user_id:(U1)
Row2=> keyword1:(K6) keyword2:(K7) keyword3:(K1) keyword4:(K2) keyword5:(K8) date:(D1) user_id:(U2)
Row3=> keyword1:(K6) keyword2:(K7) keyword3:(K1) keyword4:(K2) keyword5:(K8) date:(D2) user_id:(U2)
Row4=> keyword1:(K1) keyword2:(K2) keyword3:(K3) keyword4:(K4) keyword5:(K5) date:(D2) user_id:(U3)
Output:
K1 (2 times), K2 (2 times), on D1
K1 (2 times), K2 (2 times), on D2
Row3 should be excluded from the first count because even though the words matched, the user was a duplicate.
Here's how I've started:
<% #prophecies.each do |prophecy| %>
<% date1 = prophecy.datetwo %>
<% #prophecies.each do |prophecy| %>
<% if date1.eql?(prophecy.datetwo) == true %>
<tr>
<td><%= prophecy.keyone %></td>
<td><%= prophecy.keytwo %></td>
<td><%= prophecy.keythree %></td>
<td><%= prophecy.keyfour %></td>
<td><%= prophecy.keyfive %></td>
</tr>
<% end %>
<% end %>
<% end %>
But it's nowhere near what I'd like to accomplish. If anyone could even help me sort out the pseudocode for this I'd be happy.
First of all, it's better to do it in your model, not in your view.
You can define methods in your prophecy class something like that
def self.keywords_at_day(date)
#find prophecies for particular dae
prophecies = self.find_by(date:date)
# create hash with keywords for user
user_keywords = {}
prophecies.each do |prophecy|
user_keywords[prophecy.user] ||= []
user_keywords[prophecy.user] << prophecy.keyword
end
# create general array with all keywords
keywords = []
user_keywords.each do |user, kw|
keywords << kw.uniq
end
# count keywords
keywords_count = {}
keywords.each do |keyword|
keywords_count[keyword] ||= 0
keywords_count[keyword] += 1
end
keywords_count
end
def self.keywoards_lists
dates = Prophecy.all.map{|p| p.date}.uniq
keywords_lists = {}
dates.each do |date|
keywords_lists[date] = keywords_at_day(date)
end
keywords_lists
end
You controller
def index
#keywords_lists = Prophecy.keywords_lists
end
View
<%= #keywords_lists.each do |date, keywords_list| %>
<tr>
<td> <%= date %> </td>
<td>
<%= keywords_list.each do |keyword, count| %>
<%= "#{keyword} encountered #{count} times" %>
<% end %>
</td>
</tr>
<% end %>
If it's really not homework, I suggest you to read about MVC, ruby name convention(date_two instead of datetwo), booleans (you don't need "==true" for eql?).
And besides all it's not good type of question for stackoverflow
Cheers
My suggestion is to create a data structure that match your need. BAsically a hash where key is keyword, and content the list of uid that uniquely use your keyword:
r=[]<<{:keyword1=>"K1",keyword2:"K2",keyword3:"K3",keyword4:"k4",:date=>d1,uid:1}
r<<{:keyword1=>"K6",keyword2:"K7",keyword3:"K1",keyword4:"k2",:date=>d1,uid:2}
r<<{:keyword1=>"K6",keyword2:"K7",keyword3:"K1",keyword4:"k2",:date=>d2,uid:2}
(just for test purposes)
then:
r.inject({}) do |sum,aRow|
# loop for all keywords in the row.
[:keyword1,:keyword2,:keyword3,:keyword4,:keyword4].each do |keyword|
# get each entry or create it
sum[aRow[keyword]]=elem=sum[aRow[keyword]]||{}
count=elem[aRow[:date]]||{:users=>Set.new}
count[:users]<<aRow[:uid]
elem[aRow[:date]]=count
end
sum
end
The result if the following:
=> {"K1"=>
{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1, 2}>},
2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>}},
"K2"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"K3"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"k4"=>{2014-09-04 15:05:21 +0200=>{:users=>#<Set: {1}>}},
"K6"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}},
"K7"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}},
"k2"=>
{2014-01-01 00:00:00 +0100=>{:users=>#<Set: {2}>},
2014-09-04 15:05:21 +0200=>{:users=>#<Set: {2}>}}
So you know that keyword "K1" has been used with two different date, and by two users (1,2) for first one, and 2 for second date.
Than, it will be easy to display this array.
Related
I am trying to replace an array of names for a column of names out of a database.
I am new to Ruby on rails so it could be something simple.
This works fine:
<% students = %w(John Paul Ringo George) %>
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
This i get an error:
<% #players.each do |player| %>
<% students = player.first_name %>
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
Error:
undefined method `delete_at' for "John":String
Did you mean? delete
delete!
In the RoundRobinModule the "delete_at" what causes the error:
require 'round_robin_tournament/version'
module RoundRobinTournament
def self.schedule(array)
array.push(nil) if array.size.odd?
n = array.size
1.step(n / 2, 1).each do |i|
array.insert(n - i, array.delete_at(i))
end
pivot = array.pop
games = (n - 1).times.map do
day = [[array.first, pivot]] + (1...(n / 2)).map { |j| [array[j], array[n - 1 - j]] }
array.rotate!
day
end
array.push pivot unless pivot.nil?
games
end
end
students is supposed to be an array, yet students = player.first_name makes it a string.
I don't know if this is want you want, but the following should work:
<% students = #players.pluck(:first_name) %> # or #players.map(&:first_name)
<% teams = RoundRobinTournament.schedule(students) %>
<td><%= teams %></td>
Use .pluck if #players holds an ActiveRecord::Relation or .map if it's an array of Player objects.
But, the error tells you exactly what & where the problem is. You just need to pay attention. The code would have crashed earlier but both String and Array respond to .size.
I've been having a lot of trouble with this:
For an RPI application, all my results are within one table: results
I'm trying to print a table based on a specific data range: 2011-07-31..2012-07-01
In my controller:
class SeasonsController < ApplicationController
def s2012
#results = Result.all
#s2012 = Result.where(:date => (2011-07-31)..(2012-07-01))
end
end
In my view:
<table>
<tr>
<th>Event ID</th>
<th>Date</th>
</tr>
<% #s2012.each do |result| %>
<tr>
<td><%= result.event_id %></td>
<td><%= result.date %></td>
</tr>
<% end %>
</table>
This doesn't output any errors (small miracle), but nothing is displayed in the view. #results = Result.all prints all the whole table just fine. But how can I limit it to a specific data range?
I know you're trying to do this all ActiveRecordy, but imo it's actually less readable than if you just wrote the SQL where clause yourself.
Result.where('date BETWEEN ? AND ?',
Date.parse('2011-07-31'),
Date.parse('2012-07-01'))
maybe try:
Date.parse('2011-07-31')..Date.parse('2012-07-01')
In your current example rails will think you are doing arithmetic. You are looking at a date between the number 1973 and 2004. Instead you want to convert them to date objects first. Do
#s2012 = Result.where(:date => DateTime.parse('2011-07-31')..DateTime.parse('2012-07-01'))
I have the following models: students , groups_by_student and groups.
A row of students table is city_id, so I have to show an html table
Total group1 group2 group3
city1 30 10 5 15
city2 2 0 0 2
city3 20 10 10 0
city4 5 0 5 0
city5 10 0 2 8
This is what I did:
groups = Group.find([1,4,6]) #Array of groups id's
total = []
groups.each do |g|
total << Student.joins(:groups_by_students).where(:groups_by_students => {:group_id => g.descendants}).count(:group => :city_id)
end
#I'm using AwesomeNestedSet gem, so g.descendants gives group children.
So now I have an array of 3 hashes that contain the city id as key and the total of students as the value, but now I'm not sure how to present this data in a html table.
How can I iterate per each "total" element? or is there another way of getting this information?
Thanks in advance
Javier
EDIT:
This is the total array
total = [
{city1 =>10, city3 => 10},
{city1 => 5, city3=>10, city4=>5, city5 => 2},
{city1 => 15, city2 => 2}
]
and now I have to place each in a td label inside a html table with the 0 if theres no value for that group.
I've traversed an array of hashes like;
ary.each do |hash| puts "<tr>#{hash.keys} : #{hash.values}</tr>" end
Can you hack that to suit your needs? Am afraid your question doesn't provide a lot to work with.
This is what i did, may be it might help you a little bit: (here the total value is the last column though)
<table>
<% i = 1%>
<% total = 0%>
<% city=""%>
<% 5.times do %>
<tr>
<% city = 'city'+ "#{i}" %>
<% #total.each do |hash| %>
<% if(hash[city].nil?)%>
<% hash[city] = 0 %>
<%end%>
<% total += hash[city].to_i %>
<td><%= hash[city] %></td>
<%end %>
<td> <%= total %></td>
<% total = 0 %>
<% i += 1 %>
</tr>
<%end%>
</table>
Here the row is controlled by city and not the group. Hence i could not find any other way other than a double loop. If you need that total to be printed in the first column and then rest of the information next, then i think you need to display the total first and then loop again and display city values of each group
Also, for this you need to know the number of cities before hand or else we will not know to print '0' for a particular city in a particular group
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...
I have a books model with a date type column named publish_date. On my views I'm iterating through the books and I want to group the books by year such that I have a heading for every year and books that were published on that year to be listed below the year heading.
So by starting with "2010" all books published on 2010 would be listed, then another heading "2009" with all books published in 2009 listed below it and so forth.
<% #all_books.each do |book| %>
<%=link_to book.title + ", (PDF, " + get_file_size(book.size) + ")" %>
<% end %>
By doing a book.publish_date.strftime("%Y") I am able to get the year but I do not know how to group the entries by year. Any help on this would be appreciated.
You can use group_by (see API) like (of the top of my head
<% #all_books.group_by(&:year).each do |year, book| %>
...
<% end %>
def year
self.created_at.strftime('%Y')
end
< % #all_books.group_by(&:year).each do |year, book| %>
Year < %= year %>
# render books here
< % end %>
What say?
You can use group_by for convenience, but your need can be better served by relying on DB for sorting and a each loop. This avoids the cost of client side sorting and hash manipulations for grouping.
Somewhere in your controller
#all_books = Book.all(:order => "publish_date DESC")
In your view
<%year = nil
#all_books.each do |book|
if year.nil? or year > book.publish_date.year
year = book.publish_date.year
%>
<h1> <%=year%><h1>
<%end % >
<%=link_to book.title + ", (PDF, " + get_file_size(book.size) + ")" %>
<%end %>
The quick and dirty approach is to simply group_by the year and iterate over those:
#all_books.group_by { |b| b.created_at.year }.each do |year, books|
# All books for one year, so put heading here
books.each do |book|
# ...
end
end
This requires sorting within the Rails application, so you will need to retrieve all relevant records in order to have the data properly organized. To do the sort on the server you will probably need to introduce a year column and keep it in sync with the created_at time.