I have the query below, that will return the city and state that is the shortest distance between an inputted set of points and all rows of the table Metros:
#lat = row[latitude]
#long = row[longitude]
Metros.select(
"major_city
, major_state
,(latitude - " + #lat + ")**2 + (longitude - " + #long + ")**2 as 'distance'")
.group("major_city,major_state").limit(1).order('distance ASC')
What I need to do now is set the result to two variables row[major_city] and row[major_state] with major_city set to row[major_city] and major_state to row[major_state].
How can I accomplish this task two allow for setting to the two variables independently?
It comes out with a ActiveRecord::Relation type even if it was just one piece of result, so use .first and then take it as a single record may work.
Related
While importing from an excel file to a database, I need to format a hierarchy so it appears with leading zeros:
10.1.1.4 must be transformed into 1.010.001.001.004
I tried to iterate through and concatenate the elements:
record.hierarchy = spreadsheet.cell(i,2).split('.').each do |t|
index = index || '1.'
index = index + '.' + (((t.to_i + 1000).to_s).last(3))
end
which actually returns and array of ["10", "1", "1", "4"], not computed. I would expect this to return the last evaluated value: index
I tried to compute it directly inside the array:
record.hierarchy = '1.' + (((spreadsheet.cell(i,2).split('.').each).to_i + 1000).to_s).last(3).join('.')
which raises an undefined method to_i for enumerator.
Can someone explain me how to structure and solve this computation?
Thanks
Use #rjust.
'10.1.1.4'.split('.').map { |l| l.rjust(3, '0') }.join('.')
Your first solution uses assignment with #each. #each will not return modified array.
It is not necessary to convert the string to an array, modify the elements of the array and then join the array back into a string. The string can be modified directly using String#gsub.
str = '10.1.1.4'
('1.' + str).gsub(/(?<=\.)\d+/) { |s| sprintf("%03d", s.to_i) }
#=> "1.010.001.001.004"
See Kernel#sprintf.
(?<=\.) is positive lookbehind that requires the matched digits to be preceded by a period. I've assumed the string is known to contain between one and three digits before and after each period.
You can try different function for leading zeroes and inject to not set default value inside the loop
record.hierarchy = spreadsheet.cell(i,2).split('.').inject('1') do |result, t|
result + '.' + t.rjust(3, '0')
end
Within a graph there are Person-Nodes which have properties with information about the birthday and place of birth of a person e.g.
Jaroslavice 8.10.1679
Alcudia 26.7.1689
Is it possible to get ISO-dates and the place out of that property of type text and put it in new properties ?
It is certainly possible.
One way would be to search for nodes that do not contain your new property; then use the split function to divide the text on spaces
and periods; and then reassemble the date in the format you require.
Something like this...
MATCH (person:Person)
WHERE NOT exists(person.birthdate)
WITH person,
split(person.informations,' ')[0] AS place,
split(person.informations,' ')[1] AS date
WITH person,
place,
split(date,'.')[0] AS day,
split(date,'.')[1] AS month,
split(date,'.')[2] AS year
SET person.birth_place = place,
person.birthdate = substring('0000', 0, 4 - size(year)) + year
+ '-'
+ substring('00', 0, 2 - size(month)) + month
+ '-'
+ substring('00', 0, 2 - size(day)) + day
I am trying to figure out how inject method works
Can someone explain this
def mysort
if djeca.any?
djeca.order(name: :asc).inject([]) { |sum, c| sum += c.mysort}.uniq
else
[self]
end
mysort is method of model class Books
In controller I call method mysort :
#mybooks= Books.find_by(name: 'renesansa')
#mybookss= #mybooks.leaf_wms
djeca.order(name: :asc).inject([]) { |sum, c| sum += c.mysort}.uniq
is equivalent to
sum = []
djeca.order(name: :asc).each{|c| sum = sum + c.mysort}
sum.uniq
Adding arrays is actually concatening, so your code just appends all the c.mysort into an array.
If I understand it correctly, you could also write :
djeca.order(name: :asc).map{|c| c.mysort}.flatten.uniq
Depending on your audience, you might want to write one or the other.
Note that you don't need to assign a value to sum in the inject block, it is done automatically.
(1..10).inject(0){|mem,i| mem += i}
#=> 55
(1..10).inject(0){|mem,i| mem + i}
#=> 55
You should follow this link https://samurails.com/tips/ruby-ruby-on-rails-inject/
For example:
result = [1,2,3,4].inject(0) { |sum, number| sum + number }
Here, the process starts from 0 index to the 3 index. First inject adds 1 & 2 to get the sum of two values and stored in sum variable(i.e. sum= 3) and then it takes the sum value and adds 3 to it, to get result(i.e sum=6) and so on. Finally you will get the result like 10.
djeca.order(name: :asc)
Retrieves array of active records
.inject([])
Looping through each active record. The initial output of inject is empty array [].
{ |sum, c| }
c - each active record
sum - Inject output value. Initially its []. On each iteration the value is appended to the array. (sum += [some values])
I have a method where I add two arrays together and collect their IDs. The problem is, it's possible for one or both arrays to be null.
This is what I have:
all_items = old_duplicate_items.to_a + new_duplicate_items.to_a
all_items.map(&:id) unless all_items.blank?
Can this be improved upon?
If you're ok with an empty array as a result in the case of both input arrays being nil, then you could consolidate it as follows:
(old_duplicate_items.to_a + new_duplicate_items.to_a).map(&:id)
but that's about all I can see.
Your solution looks pretty good. Right now, it returns nil or a populated Array. If it's OK to return an empty array, you could try:
(old_duplicate_items.to_a + new_duplicate_items.to_a).map &:id
To preserve the nil return would require something at least as complex as what you have now:
(x = old_duplicate_items.to_a + new_duplicate_items.to_a).size > 0 ? x : nil
Or perhaps:
if (x = old_duplicate_items.to_a + new_duplicate_items.to_a).size > 0; x end
all_items = ((old_duplicate_items || []).to_a + (new_duplicate_items || []).to_a).map(&:id)
Here is a nested hash. We want to add all the value of "subtotal" together in ruby's way. Please be noted that the key of "0" and "1342119042142" could be any other unknown strings (number of keys is at least one. Could be more than one) when performing the addition.
{"0"=>{"lease_item_id"=>"3",
"subtotal"=>"100"},
"1342119042142"=>{"lease_item_id"=>"1",
"subtotal"=>"100",
"_destroy"=>"false"}}}
Thanks.
Like this:
set up hash:
s = {"0"=>{"lease_item_id"=>"3", "subtotal"=>"100"},
"1342119042142"=>{"lease_item_id"=>"1", "subtotal"=>"100","_destroy"=>"false"}}
calculate total:
total = s.inject(0) { |i, j| i + j.last["subtotal"].to_i}
Explanation: Look here for documentation. Basically inject is given an initial value (in the above code it is 0) and it passes the given value to the given block, where it gets set to what is returned from the block in each iteration. So in the above code, initially it is 0, on the first iteration it is set to 0 + 100 and now is equal to 100, and on the second [and final] iteration it is set to 100 + 100, 200.
Assuming h is your hash and the subtotal can be decimal value:
h.values.sum{|x| x['subtotal'].to_f}
hash = {"0"=>{"lease_item_id"=>"3", "subtotal"=>"100"}, "1342119042142"=>{"lease_item_id"=>"1", "subtotal"=>"100", "_destroy"=>"false"}}
sum = hash.values.reduce(0){|sum,inner| sum + inner["subtotal"].to_i }