2

I thought this was simple, but when it came down to this case I wasn't able to do it. I feel if I can understand this I will have a much better understanding of Ruby.

WHAT: I want to search inside a 2-d array of strings and integers, and return the index/indices of where a certain string is found. These indices of each subarray would also be placed in an array in the order of the corresponding subarrays.

Example when searching for the string "a":

Input array: [[1,"a","a",3],[1,"b"],["a",2]]

Output array: [[1,2],[],[0]]

WHAT I TRIED: Intuitively I thought it would be something like:

source = [[1,"a","a",3],[1,"b"],["a",2]]

with

source.each.each_index.select { |v| v == "a" }

or

source.each {|x| x.each_index.select { |i| x[i] == "a" }}

QUESTIONS:

1) What should I call to get my output array from my input array?

2) I see so many other enumerators and methods get mashed together this way, how come I can't do it in this case? I don't want to clutter up this question with some of the simpler test cases I tried, but I either got undefined method errors or it would just return my source array.

3) Does it have to do with what blocks are associated with which methods? I modeled my code after the answer to question: Find indices of elements that match a given condition where I am confused why it seems like the block is directly associated with multiple methods. In other words, the |i| is from the #each_index while the boolean is for the #select. Seems random and disorganized to me right now how to structure these blocks (i.e why not vice versa?).

1 Answer 1

1
source.map { |row| row.each_index.select { |i| row[i] == "a" } }
# => [[1, 2], [], [0]]
  1. You can't do it because your logic is mistaken :) source.each {...} will return source, doesn't matter what you do inside the block. To return the result, use map. source.each.each_index calls each_index on the enumerator returned by each without block, and that's not a method available on enumerators (you want each_index on arrays).

  2. Indeed. each with block and each without block will do very different things.

Specifically, in my code above:

Start with source array. map with block will process the block for each element (called row), and return an array of the results. For each row, row.each_index without block will return an iterator of all indices of the row array, select with block on the iterator will return an array that will contain only some of those elements.

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Oh so with you saying that "source.each {...} will return source", is it that even though the methods inside are returning things (e.g. #select), it will return the outermost (the most recently interpreted code) method which in this case is the #each which just returns the outer array (which is what I'm getting). However, it looks like even though #each would return itself, I can still print out the [1, 2], [], [0] result by calling source.each {|x| p x.each_index.select { |i| x[i] == "a" }}, it's just that it won't return it.
Also, since #each can be used on an enumerator (itself) it looks like I also have an option to call a .each.each and parse through to define my desired array, but it probably would be very verbose and inefficient compared to your solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.