Pavol
Pavol

Reputation: 89

'Next' keyword misunderstood in specific Ruby code

I did a small programme to count words in the array:

array = ["first line",
     "second   line",
     "",
     "  fourth line   containing  a few  more words   ",
     "fifth line "]

words = 0

array.each do |s|
  wis = 0
  s.length.times do |i|
    if i == 0
      if s[i] != " "
        wis = 1
        next #HERE IT COMES.
      end
    end
    if s[i] != " " and s[i-1] == " "
      wis += 1
    end

  end
  words += wis
end

puts "Words in the array: #{words}"

OUTPUT:

Words in the array: 13

It works properly, but there's a one thing which I can't understand. I know that next keyword leaves the current iteration but I don't know how it exactly works right here. If I omit it from the code, Output would be Words in the array: 14. I know next can be replaced with else condition and that's the problem - I don't know how to define it.

Thank you

Upvotes: 1

Views: 1184

Answers (4)

dsn raghavendra rao
dsn raghavendra rao

Reputation: 196

simple example using "next" keyword

(1..10).each do |a|
   next if a.even?
   puts a
end

output:-

1
3   
5
7
9

Usage of next in a block: When next is used within a block, it causes the block to exit immediately, returning control to the iterator method, which may then begin a new iteration by invoking the block again

Upvotes: 3

When it comes to the use of next, I suggest you to read this answer here.

About your code, I could tell you that learning Ruby requires a greater change in your way of programming. It is not just a matter of using Ruby syntax, but also of exploring Ruby potential to make things simple.

For instance, you could do your taks without any if at all.

array = ["first line",
     "second   line",
     "",
     "  fourth line   containing  a few  more words   ",
     "fifth line "]

count = array.inject(0) { |c, item| c + item.strip.split(" ").count }

puts count

This would give you

13

which is exactly the number of words, and with no if at all.

And this is not even close to be the best way. I'm sure this could be done even shorter.

Upvotes: 3

peter
peter

Reputation: 42182

Next jumps back to the beginning of the codeblock, and in this case to the next array element.

The shortest possible answer how to do this better is IMHO this

puts "Words in the array: #{array.join(' ').split(/\W+/).length}"
# Words in the array: 13

Some explanation: While working with strings it is often best to use regular expressions, to make it easy I start with combining all array elements to one string with: array.join(' ') The space is used as a separator to prevent that words are joined together. This string is split again with the regular expression between the //'s, namely \W+ which means a series of non delimiter characters (thus a word). This array is taken the length of and so giving the number of words in the string/array.

EDIT: it's two chars shorter using scan instead of split and count instead of length 8:)

array.join(' ').scan(/\W+/).count

Upvotes: 1

mikej
mikej

Reputation: 66263

As others have said, there are a lot of more elegant ways of writing a word count in Ruby. However, I'll try and answer your specific questions as there's still something to learn here.

As you've mentioned next leaves the current iteration. In your example it means that when both the i == 0 condition and the s[i] != " " condition are true then the next will execute and the if s[i] != " " and s[i-1] == " "... part will be skipped for that iteration.

The reason for getting a count of 14 words when you remove the next relies on knowing what happens when a negative index is used for a string. In this line:

if s[i] != " " and s[i-1] == " "

when i is 0 this is equivalent to

s[0] != " " and s[-1] == " "

s[-1] means the last character of the string. This is true for the line "fifth line " so the result is that the first word of that line is counted twice.

To replace the next with an else condition you'd need to arrange an alternative way for the if s[i] != " " and s[i-1] == " "... not to execute if i == 0 and s[i] != " " so something like:

if i == 0 and s[i] != " "
  wis = 1
elsif s[i] != " " and s[i-1] == " "
  wis += 1
end

Upvotes: 3

Related Questions