a beginner case question

T

Taylor Strait

I am using case in to determine the sorting method used for an array as
so:

def single_choice(object)

# sort answer order based on question.list_method
answers = object.answers

sorted_answers = case object.list_method
when 'position' then answers.sort_by {|answer| answer.position}
when 'random' then answers.sort_by {rand}
when 'alphabetical' then answers.sort_by {|answer| answer.text}
when 'reverse_alpha' then answers.sort_by {|answer| answer.text}
return answers.reverse
when 'shortest_first' then answers.sort_by {|answer|
answer.text.length}
when 'longest_first' then answers.sort_by {|answer|
answer.text.length}
return answers.reverse
end

This does not because of the return statements. However, I need to
reverse the result for those two options. How can I do this with case
statements? Or must I use if..elsif?
 
J

Jesús Gabriel y Galán

I am using case in to determine the sorting method used for an array as
so:
This does not because of the return statements. However, I need to
reverse the result for those two options. How can I do this with case
statements? Or must I use if..elsif?

You can do this:

def single_choice(object)

# sort answer order based on question.list_method
answers = object.answers

sorted_answers = case object.list_method
when 'position' then answers.sort_by {|answer| answer.position}
when 'random' then answers.sort_by {rand}
when 'alphabetical' then answers.sort_by {|answer| answer.text}
when 'reverse_alpha' then answers.sort_by {|answer| answer.text}.reverse
when 'shortest_first' then answers.sort_by {|answer| answer.text.length}
when 'longest_first' then answers.sort_by {|answer|
answer.text.length}.reverse
end
end

Jesus.
 
B

Brian Candler

Taylor said:
when 'reverse_alpha' then answers.sort_by {|answer| answer.text}
return answers.reverse

What you're doing here may be clearer if you write it out like this:

when 'reverse_alpha'
answers.sort_by {|answer| answer.text}
return answers.reverse

What's happening is (1) the answers.sort_by... line is creating a new
sorted array - and then discarding this array. (2) The last line then
returns the original 'answers' array, reversed.

You could fix this by:

when 'reverse_alpha'
answers.sort_by {|answer| answer.text}.reverse

The value of this whole expression becomes the value result of the case
statement, which in turn becomes the return value of the method.

If you really did need to use 'return' to drop straight out of the
method, you could do

when 'reverse_alpha'
answers = answers.sort_by {|answer| answer.text}
return answers.reverse

Or just:

when 'reverse_alpha'
return answers.sort_by {|answer| answer.text}.reverse
 
M

Michael Michael

I don't mean to be too intrusive as I am a dreadful IT Recruiter that
you probably all despise. I am working on filling a number of RoR
Developer positions(beginners are welcomed) for an exciting young
company in NYC. If you are interested in learning more about the
position please e-mail me, (e-mail address removed) or call me at
212.991.1835. No one has to
know that you contacted me regarding and you can still bash me here in
the blog.

Have a great day! Thanks!
 
T

Taylor Strait

Thanks Brian and Jesus - I didn't know you could .reverse a code block.
I had tried that with parenthesis but not just on the block itself.
 
J

Jesús Gabriel y Galán

Thanks Brian and Jesus - I didn't know you could .reverse a code block.
I had tried that with parenthesis but not just on the block itself.

Well, you are not reversing the code block, you are reversing the
result of the call to sort_by, which is an array.

The line is functionally identical to:

(answers.sort_by {|answer| answer.text}).reverse

The sort_by method receives no params and a block, and returns an
array. You are then calling reverse on the resulting array.
It's more clear in Brian's explanation, where he used a temporary
variable to store the result of the sort_by call.

Hope this clarifies,

Jesus.
 
F

F. Senault

Le 14 janvier 2009 à 16:56, Taylor Strait a écrit :
This does not because of the return statements. However, I need to
reverse the result for those two options. How can I do this with case
statements? Or must I use if..elsif?

To go a step further than just answering your question, I'd refactor the
whole function like this :

def single_choice(object)
l = case object.list_method
when /^position/ then lambda { |x| x.position }
when /^rand/ then lambda { rand }
when /^alpha/ then lambda { |x| x.to_s }
when /^length/ then lambda { |x| x.length }
end
sorted_answers = object.answers.sort_by(&l)
if order =~ /desc$/
sorted_answers.reverse!
end
sorted_answers
end

The lamba is there to avoid the repetition of the sort_by calls, the use
of regexpen means you have to standardize your methods (length and
length_desc vs shortest_firts and longest_first). On the other hand,
you can manage all kind of sorts without duplicating your sort method.

An even nicer form, if your arrays are of a manageable size, would be :

def single_choice(object)
r = (object.list_method =~ /desc/ ? -1 : 1)
l = case object.list_method
when /^position/ then lambda { |x, y| (x.position <=> y.position) * r }
when /^rand/ then lambda { rand }
when /^alpha/ then lambda { |x, y| (x.to_s <=> y.to_s) * r }
when /^length/ then lambda { |x, y| (x.length <=> y.length) * r }
end
object.answers.sort(&l)
end

(But sort is slower for big arrays.)

You can also extract the case expression into a helper method if you
need to sort other kinds of objects...

HTH,

Fred
 
T

Taylor Strait

F. Senault said:
To go a step further than just answering your question, I'd refactor the
whole function like this :

def single_choice(object)
l = case object.list_method
when /^position/ then lambda { |x| x.position }
when /^rand/ then lambda { rand }
when /^alpha/ then lambda { |x| x.to_s }
when /^length/ then lambda { |x| x.length }
end
sorted_answers = object.answers.sort_by(&l)
if order =~ /desc$/
sorted_answers.reverse!
end
sorted_answers
end

That is great usage of regex's -- thanks for showing me that!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,238
Members
46,826
Latest member
robinsontor

Latest Threads

Top