Parsing latitude and longitude with Ruby - ruby

I need to parse some user submitted strings containing latitudes and longitudes, under Ruby.
The result should be given in a double
Example:
08º 04' 49'' 09º 13' 12''
Result:
8.080278 9.22
I've looked to both Geokit and GeoRuby but haven't found a solution. Any hint?

"08° 04' 49'' 09° 13' 12''".gsub(/(\d+)° (\d+)' (\d+)''/) do
$1.to_f + $2.to_f/60 + $3.to_f/3600
end
#=> "8.08027777777778 9.22"
Edit: or to get the result as an array of floats:
"08° 04' 49'' 09° 13' 12''".scan(/(\d+)° (\d+)' (\d+)''/).map do |d,m,s|
d.to_f + m.to_f/60 + s.to_f/3600
end
#=> [8.08027777777778, 9.22]

How about using a regular expression? Eg:
def latlong(dms_pair)
match = dms_pair.match(/(\d\d)º (\d\d)' (\d\d)'' (\d\d)º (\d\d)' (\d\d)''/)
latitude = match[1].to_f + match[2].to_f / 60 + match[3].to_f / 3600
longitude = match[4].to_f + match[5].to_f / 60 + match[6].to_f / 3600
{:latitude=>latitude, :longitude=>longitude}
end
Here's a more complex version that copes with negative coordinates:
def dms_to_degrees(d, m, s)
degrees = d
fractional = m / 60 + s / 3600
if d > 0
degrees + fractional
else
degrees - fractional
end
end
def latlong(dms_pair)
match = dms_pair.match(/(-?\d+)º (\d+)' (\d+)'' (-?\d+)º (\d+)' (\d+)''/)
latitude = dms_to_degrees(*match[1..3].map {|x| x.to_f})
longitude = dms_to_degrees(*match[4..6].map {|x| x.to_f})
{:latitude=>latitude, :longitude=>longitude}
end

Related

How can I convert a string ("longint") to float if the number of decimals are known?

Given a lat/lon combination as string:
lat = "514525865"
lon = "54892584"
I wish to convert them to floats:
lat = 51.4525865
lon = 5.4892584
As you can see the number of decimals is KNOWN and given to be 7.
I have tried to do conversion to char-array then adding a . char then merging the char-array but that feels super irrational
def pos_to_float(stringpos)
chars = stringpos.chars
chars.insert(-8,'.')
outstring = chars.join('')
return outstring.to_f
end
lat = "514525865"
floatlat = pos_to_float(lat)
puts floatlat
> 51.4525865
no error as this works but it feels stupid.. any better functions?
You can convert to float then divide by 10^7
p lat.to_f / 10 ** 7
#=> 51.4525865

Infinite While loops in ruby

I have the following program which should count the number of years it should take a population to grow to the desired size. Whenever I run this I get an infinite loop. Can someone help me identify my error?
def pop_growth(start, percent, desired)
year_count = 0
while start <= desired
year_count += 1
start = start + (start * (percent / 100))
end
return year_count
end
I'm sure that you are trying with Integers (instead floats), so you are losing precision try this
def pop_growth(start, percent, desired)
year_count = 0
while start <= desired
year_count += 1
start = start + (start * (percent.to_f / 100))
end
return year_count
end
and let me know if it works for you. if not can you send me your start, percent and desired values?
The proper answer is given by Horacio, let me rewrite this in idiomatic ruby:
def pop_growth start, percent, desired
(0..Float::INFINITY).inject(start) do |memo, years|
break years if memo > desired
memo *= (1.0 + percent / 100.0)
end
end
or, with infinite loop:
def pop_growth start, percent, desired
loop.each_with_object(years: 0, count: start) do |_, memo|
break memo[:years] if memo[:count] > desired
memo[:years] += 1
memo[:count] *= (1.0 + percent / 100.0)
end
end
Three ways.
#1 Solve equation
Solve desired = start * (1.0 + 0.01 * percent)**n for n:
def pop_growth(start, percent, desired)
Math.log(desired.to_f/start)/Math.log(1.0 + percent/100.0)
end
years = pop_growth(100, 10, 200)
#=> 7.272540897341713
years.ceil #=> 8 if desired.
#2 Compound until desire met
def pop_growth(start, percent, desired)
return 0 if start >= desired
alpha = 1.0 + 0.01 * percent
1.step.find { (start *= alpha) >= desired }
end
pop_growth 100, 10, 200
#=> 8
#3 Use recursion
def pop_growth(start, percent, desired, years=0)
return years if start >= desired
pop_growth(start*(1.0+0.01*percent), percent, desired, years+1)
end
pop_growth 100, 10, 200
#=> 8
Just add .to_f method to percent or divide by 100.0, which will convert the integer into float.
start + (start * (percent / 100))
When you are dividing, you need at least one float number in order to return the exact division answer, else Ruby will round it down to nearest whole number, which in this case percent / 100 will result in 0, assuming that the value in percent is less than 100. This will cause this statement start + (start * (percent / 100)) to become start = start + 0, which is why you are seeing the infinite loop.

Generate hex numbers based on percentage

I'm looking for a way to generate a gradual hexadecimal color based on a percentage with Ruby.
0% = #6da94a
50% = #decc30
100% = #ce2d4a
Then programmatically generate the hexadecimal values in between those.
So I might have something like percent_to_hex(10) and that would spit out whatever hexadecimal value is 10% along the gradual gradient between 0% (green) and 50% (yellow).
Actually there is a small mistake in tralston's answer.
(x + percent * 100 * (y - x)).round
should be changed to:
(x + percent / 100.0 * (y - x)).round
Also i.to_s(16) would be a problem if you have 0 (255), as you can get a result like "ff0ff". I would recommend using "%02x" % i instead.
Here is the complete example:
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent / 100.0 * (y - x)).round
end
colors_int.map { |i| "%02x" % i }.join("")
end
Not a very polished method, but here's a good start:
# Example input: percent_to_hex(25, "abcdef", "ffffff") => "c0daf3"
def percent_to_hex(percent, start, stop)
colors = [start,stop].map do |c|
c.scan(/../).map { |s| s.to_i(16) }
end
colors_int = colors.transpose.map do |x,y|
(x + percent * 100 * (y - x)).round
end
colors_int.map { |i| i.to_s(16) }.join("")
end
Of course if you could customize it further to add or remove the leading "#" of the hex color code, etc.

How do I generate a number in a percentage range?

I am making a text adventure game and have to randomise the stats of my hero's enemies.
Is there a way to generate a random whole number from within a percentage range?
Like this: BaseHealth ± 10%, where BaseHealth is a variable.
def randomize_value(value, percent)
bottom = (value * (1 - percent / 100.0)).to_i
up = (value * (1 + percent / 100.0)).to_i
(bottom..up).to_a.sample
end
health = randomize_value(BaseHealth, 10)
This is assuming that health is to be integer.
If BaseHealth is integer,
def take_random base, percent
d = (base * percent / 100.0).to_i
base - d + rand(d * 2)
end
take_random(BaseHealth, 10)
or following Stefan's suggestion,
def take_random base, percent
d = (base * percent / 100.0).to_i
rand(base - d..base + d)
end
take_random(BaseHealth, 10)
I understand what you mean now
You can do this:
BaseHealth = ( rand(BaseHealth * 0.2) + BaseHealth*0.9 ).to_i
This can be accomplished with some basic arithmetic:
TotalHealth = BaseHealth + (BaseHealth * (rand(21)-10)/100)
This will take the BaseHealth and multiply it by a random number 0..20 minus 10, converted to a percent.
Assume BaseHealth = 20:
If rand returns 17, you get 7/100 = .07 so TotalHealth = 21.41
If rand returns 7, you get -7/100 = -.07 so TotalHealth = 18.6

ruby - simplify string multiply concatenation

s is a string, This seems very long-winded - how can i simplify this? :
if x === 2
z = s
elsif x === 3
z = s+s
elsif x === 4
z = s+s+s
elsif x === 5
z = s+s+s+s
elsif x === 6
z = s+s+s+s+s
Thanks
Something like this is the simplest and works (as seen on ideone.com):
puts 'Hello' * 3 # HelloHelloHello
s = 'Go'
x = 4
z = s * (x - 1)
puts z # GoGoGo
API links
ruby-doc.org - String: str * integer => new_str
Copy—Returns a new String containing integer copies of the receiver.
"Ho! " * 3 #=> "Ho! Ho! Ho! "
z=''
(x-1).times do
z+=s
end
Pseudo code (not ruby)
if 1 < int(x) < 7 then
z = (x-1)*s
For example for a rating system up to 5 stars you can use something like this:
def rating_to_star(rating)
'star' * rating.to_i + 'empty_star' * (5 - rating.to_i)
end

Resources