# Human-readable listing of array elements

**URL:** <https://rubytalk.org/t/human-readable-listing-of-array-elements/56573>\
**Category:** ruby-talk\
**Created:** [10 December 2009 14:15 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573 "2009-12-10T14:15:08Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Aldric\_Giacomoni2](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@Aldric\_Giacomoni2](https://rubytalk.org/u/Aldric_Giacomoni2)\
**Post date:** [10 December 2009 14:15 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/1 "2009-12-10T14:15:08Z")

</div>

This took me less than a minute to write, but I don't know if it's as  
elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
this?

def stringify array  
&nbsp;&nbsp;return array[0] if array.size == 1  
&nbsp;&nbsp;string = ""  
&nbsp;&nbsp;array.each\_with\_index do |element, index|  
&nbsp;&nbsp;&nbsp;&nbsp;case index  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when array.size - 1 # last item  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += " and #{element}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += "#{element}"  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += ", #{element}"  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
&nbsp;&nbsp;string  
end

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/](http://www.ruby-forum.com/).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [10 December 2009 14:36 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/2 "2009-12-10T14:36:31Z")

</div>

By using String#\<\< your code will become more efficient because you do  
not create new String objects all the time.

For the fun of it here are two other solutions:

irb(main):026:0\> def stringify array  
irb(main):027:1\> lead = array.slice 0...-1  
irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
array.last].join(" and ")  
irb(main):029:1\> end  
=\> nil  
irb(main):031:0\> stringify   
=\> ""  
irb(main):032:0\> stringify %w{foo}  
=\> "foo"  
irb(main):033:0\> stringify %w{foo bar}  
=\> "foo and bar"  
irb(main):034:0\> stringify %w{foo bar baz}  
=\> "foo, bar and baz"

irb(main):039:0\> def stringify array  
irb(main):040:1\> tail = array.slice -2..-1  
irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
")).join(", ") : array.first.to\_s  
irb(main):042:1\> end

irb(main):048:0\> stringify   
=\> ""  
irb(main):045:0\> stringify %w{foo}  
=\> "foo"  
irb(main):046:0\> stringify %w{foo bar}  
=\> "foo and bar"  
irb(main):047:0\> stringify %w{foo bar baz}  
=\> "foo, bar and baz"

Note, I don't claim that this is necessarily more rubyish. 🙂

Kind regards

robert

> **···**
>
> 2009/12/10 Aldric Giacomoni \<aldric@trevoke.net\>:
> 
> > This took me less than a minute to write, but I don't know if it's as  
> > elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > this?
> > 
> > def stringify array  
> > return array[0] if array.size == 1  
> > string = ""  
> > array.each\_with\_index do |element, index|  
> > case index  
> > when array.size - 1 # last item  
> > string += " and #{element}"  
> > when 0  
> > string += "#{element}"  
> > else  
> > string += ", #{element}"  
> > end  
> > end  
> > string  
> > end
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Marnen\_Laibow-Koser](https://avatars.discourse-cdn.com/v4/letter/m/a587f6/32.png) [@Marnen\_Laibow-Koser](https://rubytalk.org/u/Marnen_Laibow-Koser)\
**Post date:** [10 December 2009 15:03 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/3 "2009-12-10T15:03:59Z")

</div>

Aldric Giacomoni wrote:

> This took me less than a minute to write, but I don't know if it's as  
> elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> this?

array.inspect

Of course, that won't get you the "and".

> def stringify array  
> &nbsp;&nbsp;return array[0] if array.size == 1  
> &nbsp;&nbsp;string = ""  
> &nbsp;&nbsp;array.each\_with\_index do |element, index|  
> &nbsp;&nbsp;&nbsp;&nbsp;case index  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when array.size - 1 # last item  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += " and #{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when 0  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += "#{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += ", #{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;string

Interesting question.

class Array # or perhaps module Enumerable  
&nbsp;&nbsp;def stringify(conjunction = 'and', separator = ', ')  
&nbsp;&nbsp;&nbsp;&nbsp;if self.size \<= 1  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.to\_s  
&nbsp;&nbsp;&nbsp;&nbsp;elsif self.size == 2  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.join " #{conjunction} "  
&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array = self.dup  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;end  
end

> end

Best,

> **···**
>
> --  
> Marnen Laibow-Koser  
> [http://www.marnen.org](http://www.marnen.org)  
> marnen@marnen.org  
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![botp1](https://avatars.discourse-cdn.com/v4/letter/b/6de8d8/32.png) [@botp1](https://rubytalk.org/u/botp1)\
**Post date:** [11 December 2009 02:44 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/4 "2009-12-11T02:44:20Z")

</div>

just joing the fun of ruby,

C:\prg\>cat test3.rb

def stringify array  
&nbsp;&nbsp;string = ""  
&nbsp;&nbsp;array.each\_with\_index do |element, index|  
&nbsp;&nbsp;&nbsp;&nbsp;string \<\< case index  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when 0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;""  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when (as=array.size) - 1 # last item  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(as \< 3 ? "" : "," ) + " and "  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;", "  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end \<\< "#{element}"  
&nbsp;&nbsp;end  
&nbsp;&nbsp;string  
end

s=  
%w(this is a test). each do |element|  
&nbsp;&nbsp;p stringify(s\<\<[element])  
end

C:\prg\>ruby -W0 test3.rb  
"this"  
"this and is"  
"this, is, and a"  
"this, is, a, and test"

best regards -botp

> **···**
>
> On Thu, Dec 10, 2009 at 10:15 PM, Aldric Giacomoni \<aldric@trevoke.net\> wrote:
> 
> > This took me less than a minute to write, but I don't know if it's as  
> > elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > this?
> > 
> > def stringify array  
> > return array[0] if array.size == 1  
> > string = ""  
> > array.each\_with\_index do |element, index|  
> > case index  
> > when array.size - 1 # last item  
> > string += " and #{element}"  
> > when 0  
> > string += "#{element}"  
> > else  
> > string += ", #{element}"  
> > end  
> > end  
> > string  
> > end  
> > --

---

<div class="post-metadata">

**Author:** ![Shot\_Piotr\_Szotkowsk](https://avatars.discourse-cdn.com/v4/letter/s/c5a1d2/32.png) [@Shot\_Piotr\_Szotkowsk](https://rubytalk.org/u/Shot_Piotr_Szotkowsk)\
**Post date:** [11 December 2009 20:18 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/5 "2009-12-11T20:18:12Z")

</div>

Aldric Giacomoni:

> This took me less than a minute to write, but I don't know if it's as  
> elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> this?

> def stringify array  
> &nbsp;&nbsp;return array[0] if array.size == 1  
> &nbsp;&nbsp;string = ""  
> &nbsp;&nbsp;array.each\_with\_index do |element, index|  
> &nbsp;&nbsp;&nbsp;&nbsp;case index  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when array.size - 1 # last item  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += " and #{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;when 0  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += "#{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += ", #{element}"  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end  
> &nbsp;&nbsp;string  
> end

Couldn’t resist:

def stringify a  
&nbsp;&nbsp;a.size \< 2 ? a.first.to\_s : a[0..-2].join(', ') + " and #{a.last}"  
end

> > stringify

=\> ""

> > stringify ['Arthur']

=\> "Arthur"

> > stringify ['Arthur', 'Ford']

=\> "Arthur and Ford"

> > stringify ['Arthur', 'Ford', 'Trillian']

=\> "Arthur, Ford and Trillian"

> > stringify ['Arthur', 'Ford', 'Trillian', 'Marvin']

=\> "Arthur, Ford, Trillian and Marvin"

— Shot

> **···**
>
> --  
> a :message to you, Ruby

---

<div class="post-metadata">

**Author:** ![Aldric\_Giacomoni2](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@Aldric\_Giacomoni2](https://rubytalk.org/u/Aldric_Giacomoni2)\
**Post date:** [10 December 2009 15:01 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/6 "2009-12-10T15:01:46Z")

</div>

Robert Klemme wrote:

> By using String#\<\< your code will become more efficient because you do  
> not create new String objects all the time.

Thanks 🙂

> For the fun of it here are two other solutions:
> 
> irb(main):026:0\> def stringify array  
> irb(main):027:1\> lead = array.slice 0...-1  
> irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
> array.last].join(" and ")  
> irb(main):029:1\> end
> 
> irb(main):039:0\> def stringify array  
> irb(main):040:1\> tail = array.slice -2..-1  
> irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
> ")).join(", ") : array.first.to\_s  
> irb(main):042:1\> end
> 
> Note, I don't claim that this is necessarily more rubyish. 🙂

Your solutions \*stink\* of LISP, but maybe that's only because you're ..  
er.. processing lists.  
I like your first one - it feels more elegant than mine. The second one  
feels a little too convoluted. I also find that using 'slice' is too  
wordy, and usually just settle for array[0...-1] or array[-2..-1] -- but  
clearly that's just preference. Thanks for the further examples, I'll  
remember them (and possibly even use them someday!)

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Aldric\_Giacomoni2](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@Aldric\_Giacomoni2](https://rubytalk.org/u/Aldric_Giacomoni2)\
**Post date:** [10 December 2009 15:52 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/7 "2009-12-10T15:52:46Z")

</div>

Marnen Laibow-Koser wrote:

> Interesting question.
> 
> class Array # or perhaps module Enumerable  
> &nbsp;&nbsp;def stringify(conjunction = 'and', separator = ', ')  
> &nbsp;&nbsp;&nbsp;&nbsp;if self.size \<= 1  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.to\_s  
> &nbsp;&nbsp;&nbsp;&nbsp;elsif self.size == 2  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.join " #{conjunction} "  
> &nbsp;&nbsp;&nbsp;&nbsp;else  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array = self.dup  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
> &nbsp;&nbsp;&nbsp;&nbsp;end  
> &nbsp;&nbsp;end  
> end

It is pretty, and (like Robert's solution) handles the case where the  
array has no elements. I wouldn't put that into Enumerable though, not  
sure how it would handle a hash, for instance 🙂  
Do you think if / elsif / else is better in this situation than "case  
self.size"? What about in general?  
I know it's usually accepted that instead of several elsifs, one should  
use 'case', but I usually try to avoid 'elsif' altogether.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Richard3](https://avatars.discourse-cdn.com/v4/letter/r/b5a626/32.png) [@Richard3](https://rubytalk.org/u/Richard3)\
**Post date:** [10 December 2009 17:18 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/8 "2009-12-10T17:18:19Z")

</div>

> \> This took me less than a minute to write, but I don't know if it's as  
> \> elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> \> this?
> 
> \> def stringify array  
> \> return array[0] if array.size == 1  
> \> string = ""  
> \> array.each\_with\_index do |element, index|  
> \> case index  
> \> when array.size - 1 # last item  
> \> string += " and #{element}"  
> \> when 0  
> \> string += "#{element}"  
> \> else  
> \> string += ", #{element}"  
> \> end  
> \> end  
> \> string  
> \> end
> 
> By using String#\<\< your code will become more efficient because you do  
> not create new String objects all the time.
> 
> For the fun of it here are two other solutions:
> 
> irb(main):026:0\> def stringify array  
> irb(main):027:1\> lead = array.slice 0...-1  
> irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
> array.last].join(" and ")  
> irb(main):029:1\> end  
> =\> nil  
> irb(main):031:0\> stringify   
> =\> ""  
> irb(main):032:0\> stringify %w{foo}  
> =\> "foo"  
> irb(main):033:0\> stringify %w{foo bar}  
> =\> "foo and bar"  
> irb(main):034:0\> stringify %w{foo bar baz}  
> =\> "foo, bar and baz"
> 
> irb(main):039:0\> def stringify array  
> irb(main):040:1\> tail = array.slice -2..-1  
> irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
> ")).join(", ") : array.first.to\_s  
> irb(main):042:1\> end
> 
> irb(main):048:0\> stringify   
> =\> ""  
> irb(main):045:0\> stringify %w{foo}  
> =\> "foo"  
> irb(main):046:0\> stringify %w{foo bar}  
> =\> "foo and bar"  
> irb(main):047:0\> stringify %w{foo bar baz}  
> =\> "foo, bar and baz"
> 
> Note, I don't claim that this is necessarily more rubyish. 🙂
> 
> Kind regards
> 
> robert
> 
> --  
> remember.guy do |as, often| as.you\_can - without endhttp://blog.rubybestpractices.com/

Hey Robert,

> Note, I don't claim that this is necessarily more rubyish. 🙂

Maybe not, but I call it very clever.

Best wishes,  
Richard

> **···**
>
> On Dec 10, 9:36 am, Robert Klemme \<shortcut...@googlemail.com\> wrote:
> 
> > 2009/12/10 Aldric Giacomoni \<ald...@trevoke.net\>:

---

<div class="post-metadata">

**Author:** ![W\_James](https://avatars.discourse-cdn.com/v4/letter/w/e274bd/32.png) [@W\_James](https://rubytalk.org/u/W_James)\
**Post date:** [11 December 2009 03:05 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/9 "2009-12-11T03:05:09Z")

</div>

Sometimes it's fun to avoid using conditionals (including  
"... ? ... : ...")  
when programming.

def to\_string ary  
&nbsp;&nbsp;a = ary.dup  
&nbsp;&nbsp;a.push( a.pop(2).join " and " ).join ", "  
end

> **···**
>
> On Dec 10, 8:36 am, Robert Klemme \<shortcut...@googlemail.com\> wrote:
> 
> > 2009/12/10 Aldric Giacomoni \<ald...@trevoke.net\>:
> > 
> > \> This took me less than a minute to write, but I don't know if it's as  
> > \> elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > \> this?
> > 
> > \> def stringify array  
> > \> return array[0] if array.size == 1  
> > \> string = ""  
> > \> array.each\_with\_index do |element, index|  
> > \> case index  
> > \> when array.size - 1 # last item  
> > \> string += " and #{element}"  
> > \> when 0  
> > \> string += "#{element}"  
> > \> else  
> > \> string += ", #{element}"  
> > \> end  
> > \> end  
> > \> string  
> > \> end
> > 
> > By using String#\<\< your code will become more efficient because you do  
> > not create new String objects all the time.
> > 
> > For the fun of it here are two other solutions:
> > 
> > irb(main):026:0\> def stringify array  
> > irb(main):027:1\> lead = array.slice 0...-1  
> > irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
> > array.last].join(" and ")  
> > irb(main):029:1\> end  
> > =\> nil  
> > irb(main):031:0\> stringify   
> > =\> ""  
> > irb(main):032:0\> stringify %w{foo}  
> > =\> "foo"  
> > irb(main):033:0\> stringify %w{foo bar}  
> > =\> "foo and bar"  
> > irb(main):034:0\> stringify %w{foo bar baz}  
> > =\> "foo, bar and baz"
> > 
> > irb(main):039:0\> def stringify array  
> > irb(main):040:1\> tail = array.slice -2..-1  
> > irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
> > ")).join(", ") : array.first.to\_s  
> > irb(main):042:1\> end
> > 
> > irb(main):048:0\> stringify   
> > =\> ""  
> > irb(main):045:0\> stringify %w{foo}  
> > =\> "foo"  
> > irb(main):046:0\> stringify %w{foo bar}  
> > =\> "foo and bar"  
> > irb(main):047:0\> stringify %w{foo bar baz}  
> > =\> "foo, bar and baz"
> > 
> > Note, I don't claim that this is necessarily more rubyish. 🙂
> > 
> > Kind regards
> > 
> > robert
> > 
> > --  
> > remember.guy do |as, often| as.you\_can - without endhttp://blog.rubybestpractices.com/

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [11 December 2009 09:12 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/10 "2009-12-11T09:12:34Z")

</div>

The comma... 🙂

Cheers

robert

> **···**
>
> 2009/12/11 botp \<botpena@gmail.com\>:
> 
> > On Thu, Dec 10, 2009 at 10:15 PM, Aldric Giacomoni \<aldric@trevoke.net\> wrote:
> > 
> > > This took me less than a minute to write, but I don't know if it's as  
> > > elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > > this?
> > > 
> > > def stringify array  
> > > return array[0] if array.size == 1  
> > > string = ""  
> > > array.each\_with\_index do |element, index|  
> > > case index  
> > > when array.size - 1 # last item  
> > > string += " and #{element}"  
> > > when 0  
> > > string += "#{element}"  
> > > else  
> > > string += ", #{element}"  
> > > end  
> > > end  
> > > string  
> > > end  
> > > --
> > 
> > just joing the fun of ruby,
> > 
> > C:\prg\>cat test3.rb
> > 
> > def stringify array  
> > string = ""  
> > array.each\_with\_index do |element, index|  
> > string \<\< case index  
> > when 0  
> > ""  
> > when (as=array.size) - 1 # last item  
> > (as \< 3 ? "" : "," ) + " and "  
> > else  
> > ", "  
> > end \<\< "#{element}"  
> > end  
> > string  
> > end
> > 
> > s=  
> > %w(this is a test). each do |element|  
> > p stringify(s\<\<[element])  
> > end
> > 
> > C:\prg\>ruby -W0 test3.rb  
> > "this"  
> > "this and is"  
> > "this, is, and a"  
> > "this, is, a, and test"
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Marnen\_Laibow-Koser](https://avatars.discourse-cdn.com/v4/letter/m/a587f6/32.png) [@Marnen\_Laibow-Koser](https://rubytalk.org/u/Marnen_Laibow-Koser)\
**Post date:** [11 December 2009 20:50 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/11 "2009-12-11T20:50:28Z")

</div>

Shot (Piotr Szotkowski) wrote:

> Aldric Giacomoni:
> 
> > This took me less than a minute to write, but I don't know if it's as  
> > elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > this?
> 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string += ", #{element}"  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;end  
> > &nbsp;&nbsp;string  
> > end
> 
> Couldn’t resist:
> 
> def stringify a  
> &nbsp;&nbsp;a.size \< 2 ? a.first.to\_s : a[0..-2].join(', ') + " and #{a.last}"  
> end
> 
> > > stringify
> 
> =\> ""
> 
> > > stringify ['Arthur']
> 
> =\> "Arthur"
> 
> > > stringify ['Arthur', 'Ford']
> 
> =\> "Arthur and Ford"
> 
> > > stringify ['Arthur', 'Ford', 'Trillian']
> 
> =\> "Arthur, Ford and Trillian"
> 
> > > stringify ['Arthur', 'Ford', 'Trillian', 'Marvin']
> 
> =\> "Arthur, Ford, Trillian and Marvin"
> 
> — Shot

I like it!

Best,

> **···**
>
> --  
> Marnen Laibow-Koser  
> [http://www.marnen.org](http://www.marnen.org)  
> marnen@marnen.org  
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [10 December 2009 15:35 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/12 "2009-12-10T15:35:16Z")

</div>

> Robert Klemme wrote:
> 
> > By using String#\<\< your code will become more efficient because you do  
> > not create new String objects all the time.
> 
> Thanks 🙂
> 
> > For the fun of it here are two other solutions:
> > 
> > irb(main):026:0\> def stringify array  
> > irb(main):027:1\> lead = array.slice 0...-1  
> > irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
> > array.last].join(" and ")  
> > irb(main):029:1\> end
> > 
> > irb(main):039:0\> def stringify array  
> > irb(main):040:1\> tail = array.slice -2..-1  
> > irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
> > ")).join(", ") : array.first.to\_s  
> > irb(main):042:1\> end
> > 
> > Note, I don't claim that this is necessarily more rubyish. 🙂
> 
> Your solutions \*stink\* of LISP, but maybe that's only because you're ..  
> er.. processing lists.

Oh no. Pascal is responsible for lispish solutions - I'm not. 🙂

> I like your first one - it feels more elegant than mine. The second one  
> feels a little too convoluted.

Yep.

> I also find that using 'slice' is too  
> wordy, and usually just settle for array[0...-1] or array[-2..-1] -- but  
> clearly that's just preference.

I just felt #slice deserved a mention because it is so rarely seen.  
Initially I also thought about using #slice! which cannot be done with  
#. But then you would either modify the argument or have to dup the  
Array.

> Thanks for the further examples, I'll  
> remember them (and possibly even use them someday!)

You're welcome! Thanks for the opportunity to play around a bit. 🙂

Kind regards

robert

> **···**
>
> 2009/12/10 Aldric Giacomoni \<aldric@trevoke.net\>:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Marnen\_Laibow-Koser](https://avatars.discourse-cdn.com/v4/letter/m/a587f6/32.png) [@Marnen\_Laibow-Koser](https://rubytalk.org/u/Marnen_Laibow-Koser)\
**Post date:** [10 December 2009 16:51 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/13 "2009-12-10T16:51:34Z")

</div>

Aldric Giacomoni wrote:

> Marnen Laibow-Koser wrote:
> 
> > Interesting question.
> > 
> > class Array # or perhaps module Enumerable  
> > &nbsp;&nbsp;def stringify(conjunction = 'and', separator = ', ')  
> > &nbsp;&nbsp;&nbsp;&nbsp;if self.size \<= 1  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.to\_s  
> > &nbsp;&nbsp;&nbsp;&nbsp;elsif self.size == 2  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return self.join " #{conjunction} "  
> > &nbsp;&nbsp;&nbsp;&nbsp;else  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array = self.dup  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
> > &nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;end  
> > end
> 
> It is pretty, and (like Robert's solution) handles the case where the  
> array has no elements. I wouldn't put that into Enumerable though, not  
> sure how it would handle a hash, for instance 🙂  
> Do you think if / elsif / else is better in this situation than "case  
> self.size"?

Yes. case won't handle \<= conditions AFAIK.

> What about in general?  
> I know it's usually accepted that instead of several elsifs, one should  
> use 'case', but I usually try to avoid 'elsif' altogether.

Use whichever syntax is better suited to what you need. There's nothing  
wrong with elsif IMHO.

Best,

> **···**
>
> --  
> Marnen Laibow-Koser  
> [http://www.marnen.org](http://www.marnen.org)  
> marnen@marnen.org  
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [11 December 2009 09:14 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/14 "2009-12-11T09:14:40Z")

</div>

> > \> This took me less than a minute to write, but I don't know if it's as  
> > \> elegant as it could be. Are there more "Ruby-like ways(tm)" to write  
> > \> this?
> > 
> > \> def stringify array  
> > \> return array[0] if array.size == 1  
> > \> string = ""  
> > \> array.each\_with\_index do |element, index|  
> > \> case index  
> > \> when array.size - 1 # last item  
> > \> string += " and #{element}"  
> > \> when 0  
> > \> string += "#{element}"  
> > \> else  
> > \> string += ", #{element}"  
> > \> end  
> > \> end  
> > \> string  
> > \> end
> > 
> > By using String#\<\< your code will become more efficient because you do  
> > not create new String objects all the time.
> > 
> > For the fun of it here are two other solutions:
> > 
> > irb(main):026:0\> def stringify array  
> > irb(main):027:1\> lead = array.slice 0...-1  
> > irb(main):028:1\> lead.empty? ? array.last.to\_s : [lead.join(", "),  
> > array.last].join(" and ")  
> > irb(main):029:1\> end  
> > =\> nil  
> > irb(main):031:0\> stringify   
> > =\> ""  
> > irb(main):032:0\> stringify %w{foo}  
> > =\> "foo"  
> > irb(main):033:0\> stringify %w{foo bar}  
> > =\> "foo and bar"  
> > irb(main):034:0\> stringify %w{foo bar baz}  
> > =\> "foo, bar and baz"
> > 
> > irb(main):039:0\> def stringify array  
> > irb(main):040:1\> tail = array.slice -2..-1  
> > irb(main):041:1\> tail ? (array.slice(0...-2) \<\< tail.join(" and  
> > ")).join(", ") : array.first.to\_s  
> > irb(main):042:1\> end
> > 
> > irb(main):048:0\> stringify   
> > =\> ""  
> > irb(main):045:0\> stringify %w{foo}  
> > =\> "foo"  
> > irb(main):046:0\> stringify %w{foo bar}  
> > =\> "foo and bar"  
> > irb(main):047:0\> stringify %w{foo bar baz}  
> > =\> "foo, bar and baz"
> > 
> > Note, I don't claim that this is necessarily more rubyish. 🙂
> > 
> > Kind regards
> > 
> > robert
> > 
> > --  
> > remember.guy do |as, often| as.you\_can - without endhttp://blog.rubybestpractices.com/
> 
> Sometimes it's fun to avoid using conditionals (including  
> "... ? ... : ...")  
> when programming.

Here's one way that completely gets rid of case and if. 🙂

ALG = Hash.new( lambda {|a| [a[0...-1].join(", "), a[-1]].join(" and  
")} ).merge(  
&nbsp;&nbsp;0 =\> lambda {|a| ""},  
&nbsp;&nbsp;1 =\> lambda {|a| a.first.to\_s},  
&nbsp;&nbsp;2 =\> lambda {|a| a.join " and "}  
)

def s(a)  
&nbsp;&nbsp;ALG[a.size][a]  
end

arr =

5.times do |i|  
&nbsp;&nbsp;p arr, s(arr)  
&nbsp;&nbsp;arr \<\< "foo#{i}"  
end

> def to\_string ary  
> a = ary.dup  
> a.push( a.pop(2).join " and " ).join ", "  
> end

Nice!

Cheers

robert

> **···**
>
> 2009/12/11 w\_a\_x\_man \<w\_a\_x\_man@yahoo.com\>:
> 
> > On Dec 10, 8:36 am, Robert Klemme \<shortcut...@googlemail.com\> wrote:
> > 
> > > 2009/12/10 Aldric Giacomoni \<ald...@trevoke.net\>:
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Aldric\_Giacomoni2](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@Aldric\_Giacomoni2](https://rubytalk.org/u/Aldric_Giacomoni2)\
**Post date:** [10 December 2009 17:07 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/15 "2009-12-10T17:07:49Z")

</div>

Marnen Laibow-Koser wrote:

> Yes. case won't handle \<= conditions AFAIK.

That is a very good point, though it does handle ranges, so "case 0..1"  
would fit this particular scenario.  
Your elsif statement is probably better suited here though.

> **···**
>
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Marnen\_Laibow-Koser](https://avatars.discourse-cdn.com/v4/letter/m/a587f6/32.png) [@Marnen\_Laibow-Koser](https://rubytalk.org/u/Marnen_Laibow-Koser)\
**Post date:** [10 December 2009 17:19 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/16 "2009-12-10T17:19:18Z")

</div>

Aldric Giacomoni wrote:

> Marnen Laibow-Koser wrote:
> 
> > Yes. case won't handle \<= conditions AFAIK.
> 
> That is a very good point, though it does handle ranges, so "case 0..1"  
> would fit this particular scenario.  
> Your elsif statement is probably better suited here though.

If I'd remembered your point about ranges, I might have used case.

Best,

> **···**
>
> --  
> Marnen Laibow-Koser  
> [http://www.marnen.org](http://www.marnen.org)  
> marnen@marnen.org  
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Robert\_K1](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/robert_k1/32/1830_2.png) [@Robert\_K1](https://rubytalk.org/u/Robert_K1)\
**Post date:** [10 December 2009 17:23 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/17 "2009-12-10T17:23:35Z")

</div>

That point is not exactly true: while it doesn't out of the box, it  
can easily be made to:

irb(main):001:0\> ONE\_OR\_LESS = lambda {|n| n \<= 1}  
=\> #\<Proc:0x1014ed90@(irb):1 (lambda)\>  
irb(main):002:0\> class \<\<ONE\_OR\_LESS; alias === ; end  
=\> nil  
irb(main):003:0\> 5.times {|i| case i; when ONE\_OR\_LESS then puts  
"yow!" else puts "nah" end}  
yow!  
yow!  
nah  
nah  
nah  
=\> 5  
irb(main):004:0\>

Apart from that, the length of an Array can as a minimum become only 0  
so the same test can be done as

case array.size  
when 0,1 # \<= 1  
...  
when  
...  
end

Kind regards

robert

> **···**
>
> 2009/12/10 Aldric Giacomoni \<aldric@trevoke.net\>:
> 
> > Marnen Laibow-Koser wrote:
> > 
> > > Yes. case won't handle \<= conditions AFAIK.
> > 
> > That is a very good point, though it does handle ranges, so "case 0..1"  
> > would fit this particular scenario.  
> > Your elsif statement is probably better suited here though.
> 
> --  
> remember.guy do |as, often| as.you\_can - without end  
> [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Benoit\_Daloze](https://yyz1.discourse-cdn.com/flex029/user_avatar/rubytalk.org/benoit_daloze/32/1967_2.png) [@Benoit\_Daloze](https://rubytalk.org/u/Benoit_Daloze)\
**Post date:** [10 December 2009 17:42 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/18 "2009-12-10T17:42:30Z")

</div>

Hi,

As written in "Programming Ruby 1.9",  
You can really use case as if ... elsif ... else ... end

So, in our case:

if self.size \<= 1  
&nbsp;&nbsp;return self.to\_s  
elsif self.size == 2  
&nbsp;&nbsp;return self.join " #{conjunction} "  
else  
&nbsp;&nbsp;array = self.dup  
&nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
&nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
end

becomes:

case  
when self.size \<= 1  
&nbsp;&nbsp;return self.to\_s  
when self.size == 2  
&nbsp;&nbsp;return self.join " #{conjunction} "  
else  
&nbsp;&nbsp;array = self.dup  
&nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
&nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
end

Well, that's not especially better I think, but it looks cool and a little  
less 'procedural' to me.

Anyway, I'm wondering how case manage the comma(,), is it acting like a OR  
on each of the elements? I thought first to Array#=== but that isn't  
defined. So, is it sort of syntactic sugar ?

> **···**
>
> 2009/12/10 Robert Klemme \<shortcutter@googlemail.com\>
> 
> > 2009/12/10 Aldric Giacomoni \<aldric@trevoke.net\>:  
> > \> Marnen Laibow-Koser wrote:  
> > \>\>  
> > \>\> Yes. case won't handle \<= conditions AFAIK.  
> > \>  
> > \> That is a very good point, though it does handle ranges, so "case 0..1"  
> > \> would fit this particular scenario.  
> > \> Your elsif statement is probably better suited here though.
> > 
> > That point is not exactly true: while it doesn't out of the box, it  
> > can easily be made to:
> > 
> > irb(main):001:0\> ONE\_OR\_LESS = lambda {|n| n \<= 1}  
> > =\> #\<Proc:0x1014ed90@(irb):1 (lambda)\>  
> > irb(main):002:0\> class \<\<ONE\_OR\_LESS; alias === ; end  
> > =\> nil  
> > irb(main):003:0\> 5.times {|i| case i; when ONE\_OR\_LESS then puts  
> > "yow!" else puts "nah" end}  
> > yow!  
> > yow!  
> > nah  
> > nah  
> > nah  
> > =\> 5  
> > irb(main):004:0\>
> > 
> > Apart from that, the length of an Array can as a minimum become only 0  
> > so the same test can be done as
> > 
> > case array.size  
> > when 0,1 # \<= 1  
> > ...  
> > when  
> > ...  
> > end
> > 
> > Kind regards
> > 
> > robert
> > 
> > --  
> > remember.guy do |as, often| as.you\_can - without end  
> > [http://blog.rubybestpractices.com/](http://blog.rubybestpractices.com/)

---

<div class="post-metadata">

**Author:** ![Aldric\_Giacomoni2](https://avatars.discourse-cdn.com/v4/letter/a/91b2a8/32.png) [@Aldric\_Giacomoni2](https://rubytalk.org/u/Aldric_Giacomoni2)\
**Post date:** [10 December 2009 17:48 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/19 "2009-12-10T17:48:30Z")

</div>

Robert Klemme wrote:

> > Marnen Laibow-Koser wrote:
> > 
> > > Yes. �case won't handle \<= conditions AFAIK.
> > 
> > That is a very good point, though it does handle ranges, so "case 0..1"  
> > would fit this particular scenario.  
> > Your elsif statement is probably better suited here though.
> 
> That point is not exactly true: while it doesn't out of the box...

c:\\>irb  
irb(main):001:0\> RUBY\_VERSION  
=\> "1.8.7"  
irb(main):002:0\> 5.times { |a| case a; when 0..2 then puts "yow" else  
puts "nah" end }  
yow  
yow  
yow  
nah  
nah  
=\> 5  
irb(main):003:0\>

Alright.. Well then, I'm confused.

> **···**
>
> > 2009/12/10 Aldric Giacomoni \<aldric@trevoke.net\>:
> 
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

---

<div class="post-metadata">

**Author:** ![Marnen\_Laibow-Koser](https://avatars.discourse-cdn.com/v4/letter/m/a587f6/32.png) [@Marnen\_Laibow-Koser](https://rubytalk.org/u/Marnen_Laibow-Koser)\
**Post date:** [10 December 2009 17:49 UTC](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573/20 "2009-12-10T17:49:19Z")

</div>

Benoit Daloze wrote:

> Hi,
> 
> As written in "Programming Ruby 1.9",  
> You can really use case as if ... elsif ... else ... end
> 
> So, in our case:
> 
> if self.size \<= 1  
> &nbsp;&nbsp;return self.to\_s  
> elsif self.size == 2  
> &nbsp;&nbsp;return self.join " #{conjunction} "  
> else  
> &nbsp;&nbsp;array = self.dup  
> &nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
> &nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
> end
> 
> becomes:
> 
> case  
> when self.size \<= 1  
> &nbsp;&nbsp;return self.to\_s  
> when self.size == 2  
> &nbsp;&nbsp;return self.join " #{conjunction} "  
> else  
> &nbsp;&nbsp;array = self.dup  
> &nbsp;&nbsp;array[-1] = [conjunction, array[-1]].join ' '  
> &nbsp;&nbsp;array.join separator # proper English usage has comma before 'and'  
> end

Thanks, I had forgotten about that too.

> Well, that's not especially better I think, but it looks cool and a  
> little  
> less 'procedural' to me.

It's no less procedural, and in fact it uses another line of code for no  
advantage that I can see.

If you truly want this to look less procedural, I think you'd need to  
somehow implement a polymorphic dispatch based on Array.size...but let's  
not go there. 🙂

> Anyway, I'm wondering how case manage the comma(,), is it acting like a  
> OR  
> on each of the elements? I thought first to Array#=== but that isn't  
> defined. So, is it sort of syntactic sugar ?

Best,

> **···**
>
> > 2009/12/10 Robert Klemme \<shortcutter@googlemail.com\>
> 
> --  
> Marnen Laibow-Koser  
> [http://www.marnen.org](http://www.marnen.org)  
> marnen@marnen.org  
> --  
> Posted via [http://www.ruby-forum.com/\](http://www.ruby-forum.com/%5C).

[Next page](https://rubytalk.org/t/human-readable-listing-of-array-elements/56573.md?page=2)
