1

I was wondering if it is possible to return to an Each iterator in Ruby from within a for-loop placed within the block passed to Each.

def find member = ""

        productHash = {}

            #@entries is a hash, with both the keys and values being strings
            #the member parameter is a string

        @entries.each do |key, value|

            for i in 0...member.size

                if(key[i] != member[i])
                    next #the next keyword doesn't work...all it does is return to the for iterator.  I'm looking for a keyword that would return to the each iterator, and allow each to pass back in the next key-value pair.
                end

            end

            productHash[key] = value


        end

        productHash

end

What I'm trying to accomplish is this: the moment I see that a character in the member parameter doesn't match the corresponding character in a given key, I move on to the next key-value pair.

voltair
  • 615
  • 2
  • 7
  • 21
  • 2
    Why are you using a for loop? Why don't you do an each method with a block? – thank_you Apr 30 '13 at 23:36
  • @jason328 How would that help? The issue would still be the same I believe. And the reason I'm using a for loop here is so that I can keep track of the index number for purposes of comparing to the corresponding character in the parameter "member". I guess conceptually my question is whether any of the return statements (such as break, next, return) discriminate between a for-loop iterator and an each iterator. – voltair Apr 30 '13 at 23:44
  • I'm having a hard time understanding your question. Would using `each_with_index` help you at all? – thank_you Apr 30 '13 at 23:51
  • What is `member`? An array? – squiguy Apr 30 '13 at 23:57
  • It looks like it. I suspect it's pseudo code as there is no way that method could work without some parameters added. – thank_you May 01 '13 at 00:04
  • The reason your question is difficult to understand is that it makes a number of assumptions about data that aren't reflected in how your code is structured: 1. `member`: this is either a hash or an array. 2. `@entries`: probably a hash, given the block arguments. 3. The `key` of each entry is another hash or array. 4. As it's written, your method doesn't care about the for loop; it's just going to return a duplicate of `@entries`. Be more explicit about what you want to do. Provide examples for your variables, and what you expect as the outcome (or better yet, a test) – Zach Kemp May 01 '13 at 00:04
  • I added in clarification in comments within the code. The Member parameter is a string, and the keys and values are also strings (I apologize for not clarifying that earlier). @jason328 the code was not pseudocode though. Setting a default value to member was not necessary, although it definitely improves clarity. – voltair May 01 '13 at 01:40

1 Answers1

1

It looks like you're trying to do some kind of comparison where if the key matches a particular prefix specified by member then you would make an assignment.

This code should be functionally similar:

def find(member = "")
  hash = { }

  @entries.each do |key, value|
    # Unless key begins with prefix, skip it.
    next unless (key[0, prefix.length] == prefix)

    hash[key] = value
  end

  hash
end

There's no official goto statement in Ruby, and many would argue this is a good thing, but it means that busting out of nested blocks can be a bit tricky.

Still, if you approach the problem in the right way, there's almost always a solution that's elegant enough.

Update:

To break out of nested loops, an approach might be:

list.each do |i|
  broken = false

  inner_list.each do |j|
    if (j > 10)
      broken = true
      break
    end
  end

  break if (broken)
end
tadman
  • 208,517
  • 23
  • 234
  • 262
  • thank you so much! just to verify, is there no way to exit from within the for-loop to the each iterator in my code? – voltair May 01 '13 at 02:38
  • To be honest, nobody uses `for` in Ruby except people who've ever used Ruby before. The `each` iterator, or something else from Enumerable, is used instead. To kick out of two levels, `return` will usually do the trick if you can exit the method immediately. As an alternative, set a flag and `break`, then `break` again if that condition is set. – tadman May 01 '13 at 02:43
  • I've amended my answer with a short example of that. – tadman May 01 '13 at 02:46
  • this makes sense. i guess my question conceptually boiled down to whether or not any of the keywords *return, break, and next* discriminated between a for-loop and the each method. it looks like they don't, so setting a flag will always be necessary. – voltair May 01 '13 at 02:52
  • Yeah, they only affect the current loop context. Some other languages support a `break` that has an optional target label, but Ruby does not. – tadman May 01 '13 at 02:56
  • Using throw and catch is usually considered the correct way to break out of deeply nested loops, and even deeply nested method calls. See http://stackoverflow.com/questions/1352120/how-to-break-outer-cycle-in-ruby – davogones May 01 '13 at 03:34
  • That's interesting, but I'd use that as a last-resort. Usually if you've dug a hole deep enough you need that to get out of it, the design of your logic should be simplified. In this case, it's massive overkill. Packaging this simple logic in a method that can call `return` is by far the most straight-forward and easily testable approach. – tadman May 01 '13 at 04:17