I've got the following code, which works, but seems repetitive. Under DRY principle, how can I clean this up?
puts "Blurt out a word"
word = gets.chomp
word_list = []
word_list.push word
until word == ""
word = gets.chomp
word_list.push word
end
puts word_list.sort
3 Answers 3
puts "Blurt out a word"
word_list = []
while word_list.last != ""
word_list << gets.chomp
end
puts word_list.sort
If you prefer the until
:
puts "Blurt out a word"
word_list = []
until word_list.last == ""
word_list << gets.chomp
end
puts word_list.sort
You can also do it shorter:
puts "Blurt out a word"
word_list = []
word_list << gets.chomp until word_list.last == ""
puts word_list.sort
Remark: The last (empty) line is also returned. To skip the empty line you may use:
puts word_list[0..-2].sort
Perhaps
puts 'Blurt..'
puts STDIN.take_while{|line| line !~ /^$/}.map(&:chomp).sort
Edit: Why is this better? Because unlike other approaches it never modifies a variable that is assigned once. Thus it preserves the referential integrity. That is this is a functional programming approach in comparison with others which (as of now) follow an imperative model. The succinctness that results from it is just a bonus.
-
\$\begingroup\$ you code solo, don't you? \$\endgroup\$Ryan Miller– Ryan Miller2012年08月15日 19:24:41 +00:00Commented Aug 15, 2012 at 19:24
-
\$\begingroup\$ too hard to read? \$\endgroup\$Rahul Gopinath– Rahul Gopinath2012年08月16日 02:51:15 +00:00Commented Aug 16, 2012 at 2:51
-
\$\begingroup\$ i can read it just fine, understanding what it is doing is taking a lot longer than it should. \$\endgroup\$Ryan Miller– Ryan Miller2012年08月16日 13:55:27 +00:00Commented Aug 16, 2012 at 13:55
-
\$\begingroup\$ +1. @Ryan: This is simple functional programming style, IMO we should expect a competent team to have no problems with it. @rahul: If you have the abstraction
String#present?
you can even write a slightly more declarativeSTDIN.take_while(&:present?).map(&:chomp).sort
. \$\endgroup\$tokland– tokland2012年08月25日 19:26:44 +00:00Commented Aug 25, 2012 at 19:26
Keeping as much of your style as possible, the simple way to avoid repetition is to pull the repetitive phrases inside your loop.
Now I'm assuming that what prevented you from doing this was the fact that Ruby's 'until' loop evaluates the exit condition at the top of the loop, which will therefore throw an error unless you've initialised 'word'.
This inconvenience can be avoided by moving from an 'until' loop to an infinite loop with an internal test / decision / exit condition, like so:
puts "Blurt out a word"
word_list = []
loop do
word= gets.chomp
if word == ""
break
else
word_list.push word
end
end
puts word_list.sort
Now 'word' is defined before the exit condition is evaluated. And as a useful aside, a blank entry is not inserted into 'word_list'.
There are of course many other ways of doing this -- Ruby allows for cleverness over clarity. The above simply refactors your code and removes the repetition.