# A beginner case question

**URL:** <https://www.ruby-forum.com/t/a-beginner-case-question/157702>\
**Category:** Ruby\
**Created:** [January 14, 2009, 4:57pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702 "2009-01-14T16:57:50Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 4:57pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/1 "2009-01-14T16:57:50Z")

</div>

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?

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 5:12pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/2 "2009-01-14T17:12:44Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 5:18pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/3 "2009-01-14T17:18:42Z")

</div>

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, removed\_email\_address@domain.invalid 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?

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 5:26pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/4 "2009-01-14T17:26:45Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 5:13pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/5 "2009-01-14T17:13:01Z")

</div>

On Wed, Jan 14, 2009 at 4:56 PM, Taylor S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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.

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 5:38pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/6 "2009-01-14T17:38:21Z")

</div>

On Wed, Jan 14, 2009 at 5:26 PM, Taylor S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
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.

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 11:40pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/7 "2009-01-14T23:40:59Z")

</div>

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

---

<div class="post-metadata">

**Author:** ![taylorstrait](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b5a626/32.png) [@taylorstrait](https://www.ruby-forum.com/u/taylorstrait)\
**Post date:** [January 14, 2009, 11:51pm UTC](https://www.ruby-forum.com/t/a-beginner-case-question/157702/8 "2009-01-14T23:51:49Z")

</div>

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!
