Ruby csv import get code smaller but equal - ruby-on-rails

I'm new to rails and ruby...
How can i refactor such code, which import's from csv file data?
Now i have such code
if row[qnt].to_s != ""
eqnt = /(\d+)/.match(row[qnt])[0].to_s
else
eqnt = 0
end
I try something like
if row[qnt].present?
eqnt = /(\d+)/.match(row[qnt])[0].to_s
else
eqnt = 0
end
But is it equal, and also what else could i do to get code smaller?

How about this?
row[qnt].present? ? eqnt = /(\d+)/.match(row[qnt])[0].to_s : eqnt = 0

I'm not convinced the code gains readability by trying to compress it much further.
eqnt = row[qnt].present? ? /(\d+)/.match(row[qnt])[0].to_s : 0
Or
eqnt = 0
eqnt = /(\d+)/.match(row[qnt])[0].to_s if row[qnt].present?
Or
theRow = row[qnt]
eqnt = theRow.present? ? /(\d+)/.match(theRow).first.to_s : 0
Or better yet, extract this into a method, keep the mainline code clean, and isolate the logic.
I'm not psyched about eqnt ending up with different types, though, unless that's by design.

eqnt = (/(\d+)/.match(row[qnt]) || [0])[0]

Related

Removing nested [quote] tags in ruby

I'm writing a forum application in Rails and I'm stuck on limiting nested quotes.
I'm try to use regex and recursion, going down to each matching tag, counting the levels and if the current level is > max, deleting everything inside of it. Problem is that my regex is only matching the first [ quote ] with the first seen [ /quote ], and not the last as intended.
The regex is just a slight tweak of what was given in the docs of the custom bbcode library I'm using (I know very little about regex, I've tried to learn as much as I can in the past couple days but I'm still stuck). I changed it so it'd include [quote], [quote=name] and [quote=name;222] . Could someone examine my code and let me know what the problem could be? I'd appreciate it lots.
def remove_nested_quotes(post_string, max_quotes, count)
result = post_string.match(/\[quote(:.*)?(?:)?(.*?)(?:)?\](.*?)\[\/quote\1?\]/mi)
if result.nil?
return false
elsif (count = count+1) > max_quotes
full_str = result[0]
offset_beg = result.begin(3)
offset_end = result.end(3)
excess_quotes = full_str[offset_beg ..offset_end ]
new_string = full_str.slice(excess_quotes )
return new_string
else
offset_beg = result.begin(3)
offset_end = result.end(3)
full_str = result[0]
inner_string = full_str[offset_beg..offset_end]
return remove_nested_quotes(inner_string , max, count)
end
end
I mean something like
counter = 0
max = 5
loop do
matched = false
string.match /endquote|quote/ do |match|
matched = true
if endquote matched
counter -= 1
else # quote matched
counter += 1
end
if counter > max
# Do something, break or return
else
string = match.post_match
end
end
break unless matched
end

Ruby Simulated Annealing Trouble

I'm trying to implement a simulated annealing on ruby based on a TSP in which i tried to solve (i converted this code from java). However it turns out the annealing is making my results worst! (PlayerPath gives me a path in which i'll do an Simulated annealing on - i got the path by carrying out a greedy algorithm 1). Can someone help me check on the code and see if i've got something wrong or is it just that simulated annealing doesnt always make things better?
#BEGIN ANNEALING
for i in 1..k
temp = 10000000
cooling = 0.003
if (playerPath[i].length > 2) # if path is larger than 2
bestPath = playerPath[i]
while temp > 1
newSolution = playerPath[i];
firstPosition = rand(newSolution.length)
secondPosition = rand(newSolution.length)
if(firstPosition == 0 || firstPosition == newSolution.length-1)
next
end
if(secondPosition == 0 || secondPosition == newSolution.length-1 )
next
end
# swap cities
tempStore = newSolution[firstPosition]
newSolution[firstPosition] = newSolution[secondPosition]
newSolution[secondPosition] = tempStore
# Tabulation
currentEnergy = calculate_distance(playerPath[i])
neighbourEnergy = calculate_distance(newSolution)
if(acceptanceProbability(currentEnergy,neighbourEnergy,temp) > rand)
playerPath[i] = newSolution
end
if(calculate_distance(playerPath[i])< calculate_distance(bestPath))
bestPath = playerPath[i];
end
temp *= (1-cooling);
end
end
end
#END ANNEALING
#acceptanceProbability
def acceptanceProbability(energy, newEnergy,temperature)
# If the new solution is better, accept it
if (newEnergy < energy)
return 1.0
end
# If the new solution is worse, calculate an acceptance probability
return Math.exp((energy - newEnergy) / temperature)
end

Easier way to write If hash includes then - Ruby

I have the following in an initialize method on my model:
#home_phone = contact_hash.fetch('HomePhone')
However, sometimes I need this instead:
#home_phone = contact_hash.fetch('number')
Also, sometimes neither of those will be true and I will need the home_phone attribute to be empty.
How can I write this out without creating a big loop like so:
if contact_hash.has_key?('HomePhone')
#home_phone = contact_hash.fetch('HomePhone')
elsif contact_hash.has_key?('number')
#home_phone = contact_hash.fetch('number')
else
#home_phone = ""
end
You could try
#home_phone = contact_hash.fetch('HomePhone', contact_hash.fetch('number', ""))
or better
#home_phone = contact_hash['HomePhone'] || contact_hash['number'] || ""
contact_hash.values_at('HomePhone','number','home_phone').compact.first
Edit:
My first solution did not really give the answer asked for. Here is a modified version, although I think in the case of only 3 options the solution given by #knut is better.
contact_hash.values_at('HomePhone','number').push('').compact.first
def doit(h, *args)
args.each {|a| return h[a] if h[a]}
""
end
contact_hash = {'Almost HomePhone'=>1, 'number'=>7}
doit(contact_hash, 'HomePhone', 'number') # => 7
You could use values_at I suppose:
#home_phone = contact_hash.values_at('HomePhone', 'number').find(&:present?).to_s
That isn't exactly shorter but it wouldn't be convenient if you had the keys in an array:
try_these = %w[HomePhone number]
#home_phone = contact_hash.values_at(*try_these).find(&:present?).to_s
You could also wrap that up in a utility method somewhere or patch it into Hash.

Rails DateTime Conversion and Time Comparison

I am having a bit of trouble with comparing times in Rails. I want to check to see if an event lies within a window, if it does, then find which, the event or window starts last and which ends first. My code is as follows.
startingTime = 0
endingTime = 0
time = 0
eventTimeStart = Time.parse(event.start.to_s) #Need to convert DateTime to just Time
windowTimeStart = Time.parse(application.reportStart.to_s)
eventTimeEnd = Time.parse(event.end.to_s) #Need to convert DateTime to just Time
windowTimeEnd = Time.parse(application.reportEnd.to_s)
days = 0
if((windowTimeStart > eventTimeStart) || !(eventTimeStart < windowTimeEnd))
startingTime = windowTimeStart
if((eventTimeStart > windowTimeEnd))
days -= 1
end
else
startingTime = eventTimeStart
end
if((windowTimeEnd > eventTimeEnd) && (eventTimeEnd > windowTimeStart))
endingTime = eventTimeEnd
else
if((eventTimeEnd < windowTimeStart))
days -= 1
end
endingTime = windowTimeEnd
end
I have handwritten out each case, however at runtime it seems to run different from expected. It seems as if I always get into the windowed times. Does Rails use a different approach to Times than what I'm thinking? Can you even compare times in this manner?
If you are trying to see whether intervals overlap or not, this simple check will do:
overlaps = interval_1_start < interval_2_end && interval_1_end > interval_2_start
I don't understand the rest of the question, but I just hope that you don't have two big loops for event and application around the code you have pasted above.
Thanks for your suggestion Mladen.
In order to get this working, I passed all of the time objects into a method I made that converted them into minutes.
def self.getMin(time)
return((time.hour*60) + time.min)
end
I called that on all of my checks and now it seems to work.
if((getMin(windowTimeStart) > getMin(eventTimeStart)) || !(getMin(eventTimeStart) < getMin(windowTimeEnd)))
startingTime = windowTimeStart
if((getMin(eventTimeStart) > getMin(windowTimeEnd)))
days -= 1
end
else
startingTime = eventTimeStart
end
I'm sure there is a better way to check, however it does work now.

Rails - IF Block with complex statements, how to optimize w/o reducing Readability?

in ruby/rails3, I need to do some heavy text parsing to find a certain string. Right now I'm doing something like the following:
extract_type1 = body.scan(/(stuff)/m).size
extract_type2 = body.scan(/(stuff)/m).size
extract_type3 = body.scan(/(stuff)/m).size
extract_type4 = body.scan(/(stuff)/m).size
extract_type5 = body.scan(/(stuff)/m).size
if extract_type1 > 0
elsif extract_type2 > 0
elsif extract_type3 > 0
elsif extract_type4 > 0
elsif extract_type5 > 0
The problem here is that I keep needing to add extract types based on the app. And that results in a lot of processing when the case occurs that extract_type1 >0 and the rest aren't needed.
But at the same time, it's nice and clean to have the extract logic separated from the if block as that would be busy messy and hard to read.
Any thoughts on how to optimize this while not compromising readability?
Thanks
what about storing all your "keywords" you are searching for in an array and iterate over it like:
stuff = ["stuff1", "stuff2"]
stuff.each do |c_stuff|
if body.scan(/(#{Regexp.escape(c_stuff)})/m).size > 0
# do something
# break the loop
break
end
end
Edit: If you need the index of the element, you can use each_with_index do |c_stuff, c_index|
Lazy evaluation might work for you; just convert your extract_X variables to lambdas so that the values are computed on use:
extract_type1 = lambda { body.scan(/(stuff)/m).size }
extract_type2 = lambda { body.scan(/(stuff)/m).size }
extract_type3 = lambda { body.scan(/(stuff)/m).size }
extract_type4 = lambda { body.scan(/(stuff)/m).size }
extract_type5 = lambda { body.scan(/(stuff)/m).size }
if extract_type1.call > 0
elsif extract_type2.call > 0
elsif extract_type3.call > 0
elsif extract_type4.call > 0
elsif extract_type5.call > 0
If you're using the extract_X values more than once then you can add memoization to the lambdas so that the values are computed on first access and then cached so that subsequent accesses would just use the value that was already computed.

Resources