A beginner case question

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?

Taylor S. wrote:

  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

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, [email protected] 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!

Taylor S. wrote:

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?

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.

On Wed, Jan 14, 2009 at 4:56 PM, Taylor S. [email protected]
wrote:

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.

On Wed, Jan 14, 2009 at 5:26 PM, Taylor S. [email protected]
wrote:

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.

Le 14 janvier 2009 à 16:56, Taylor S. 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

F. Senault wrote:

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!