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™” 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
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!)
array.last].join(" and ")
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.
class Array # or perhaps module Enumerable
def stringify(conjunction = ‘and’, separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
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.
class Array # or perhaps module Enumerable
def stringify(conjunction = ‘and’, separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
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.
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 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.
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™” to write
this?
array.inspect
Of course, that won’t get you the “and”.
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
Interesting question.
class Array # or perhaps module Enumerable
def stringify(conjunction = ‘and’, separator = ', ')
if self.size <= 1
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
end
end
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
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>
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
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
becomes:
case
when self.size <= 1
return self.to_s
when self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
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 ?
On 12/10/2009 06:49 PM, Marnen Laibow-Koser wrote:
Benoit D. wrote:
array = self.dup
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
Thanks, I had forgotten about that too.
Me, 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.
The advantage for me is that “case” conveys a different notion: I am
reminded of SQL’s case which is an expression, i.e. you get a single
value out of several based on conditions after “where”. “if elsif else
end” is more about executing different procedural sequences. The
difference is less technical and more informal.
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.
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
return self.to_s
elsif self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
array.join separator # proper English usage has comma before ‘and’
end
becomes:
case
when self.size <= 1
return self.to_s
when self.size == 2
return self.join " #{conjunction} "
else
array = self.dup
array[-1] = [conjunction, array[-1]].join ’ ’
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 ?
On Thu, Dec 10, 2009 at 10:15 PM, Aldric G. [email protected]
wrote:
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”
array.each_with_index do |element, index|
end
irb(main):029:1> end
irb(main):039:0> def stringify array
=> “foo and bar”
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.