Ruby Array Sort 2 different ways -


i have array of objects i'm trying sort multiple criteria. of comparisons doing <=> on hashes, using sort_by fast, 1 of them more complex.

the array of soccer teams, , it's being sorted this:

teams.sort_by { |item| [item.points, item.goal_dif, item.goals] } 

however, in case @ last 2 teams have identical values on 3 fields, want tiebreaker function made, a_beat_b(teama, teamb).

i tried using array.sort, it's extremely slow compared sort_by first few... implementation this:

teams.sort ( |a,b| [a.points, a.goals_dif, a.goals] <=> [b.points, b.goals_dif, b.goals])
slow compared sort_by. functions points, goals_dif , goals require simple queries, gets bogged down if has hundreds.

i'm not @ ruby, not sure put a_beats_b in there. (it returns 1, 0 or -1 if beat, drew or lost b, repsectively)

i tried using array.sort, it's extremely slow compared sort_by first few

this because sort calls given block several times. here's example show what's going on under hood: (sorting "apple", "pear" , "fig" length)

def length(str)   puts "calculating #{str.inspect}.length"   str.length end  array = %w{apple pear fig} array.sort { |a, b| length(a) <=> length(b) } #=> ["fig", "pear", "apple"] 

output our length method:

calculating "apple".length calculating "pear".length calculating "apple".length calculating "fig".length calculating "pear".length calculating "fig".length 

as can see, length called multiple times during sort. imagine these database queries.

sort_by on other hand calls block once each element, building internal mapping:

array.sort_by { |a| length(a) } #=> ["fig", "pear", "apple"] 

output:

calculating "apple".length calculating "pear".length calculating "fig".length 

for expensive operations (like database queries), faster. it's less flexible – can't dynamically compare a , b more.

you can store results of (expensive) operation, example using hash: (this called memoization)

hash = hash.new { |h, k| h[k] = length(k) } 

and use hash within sort:

array.sort { |a, b| hash[a] <=> hash[b] } # calculating "apple".length # calculating "pear".length # calculating "fig".length #=> ["fig", "pear", "apple"] 

after sort, our hash looks this:

hash #=> {"apple"=>5, "pear"=>4, "fig"=>3} 

applied code, should work:

hash = hash.new { |h, k| h[k] = [k.points, k.goal_dif, k.goals] } teams.sort { |a, b| hash[a] == hash[b] ? a_beats_b(a, b) : hash[a] <=> hash[b] } 

Comments

Popular posts from this blog

serialization - Convert Any type in scala to Array[Byte] and back -

matplotlib support failed in PyCharm on OSX -

python - Matplotlib: TypeError: 'AxesSubplot' object is not callable -