4

I have to sort through a (rows)array of (row)arrays. The (row)arrays contain an arbitrary number of strings. If a (row)array contains only empty strings I want to remove it from the (rows)array.

I'm currently doing this:

rows.each do |row|

  row.each_index do |i|

   if row[i].length > 0
    break 
   elsif i == row.count-1
    rows.delete(row)
   end

  end

end

But is there a more elegant way to do it?

6 Answers 6

5

Slightly more concise:

rows.reject! { |row| row.all?(&:empty?) }
Sign up to request clarification or add additional context in comments.

3 Comments

When calling a method, &expression means "evaluate expression, call to_proc on whatever it returns, and use the value returned by to_proc as the block for this method call". Symbol#to_proc works like this: :method_name.to_proc returns an anonymous function which is just like { |x| x.method_name }.
So when you are passing a block which looks like { |x| x.method }, you can always compress that down to &:method, which should go last in the list of arguments.
Nice further discussion of & / to_proc here: stackoverflow.com/questions/1961030/…
4

Modifying an array while you iterate though it is not a good idea - you may find your code skips certain elements or does weird stuff. I'd do

rows.reject! {|row| row.all? {|row_element| row_element.empty?}}

We reject a row if the block row_element.empty? evaluates to true for all elements in the row. It's well worth getting familiar with all of the methods in Enumerable, they're very handy for this sort of task.

7 Comments

It's better to use blank? instead of empty? in case one of elements is nil, blank? will return true, while empty? will error out
Thanks a lot. For clarity please edit your answer to show that this will return a new array, leaving rows untouched because you used reject instead of reject! Did you do this because using reject! would cause rows to be modified during iteration?
+1 Since the OP asked for an elegant solution, not to say yours is not, it is perfectly fine, consider this: rows.reject{ |row| row.all? &:empty? }
@iouri blank? is a railsism, although I suppose the question is tagged rails too. 1ndivisible - didn't realise you were interested in doing it in place - that works too
Actually I think rows.reject! would be bad in this situation as 'The array is changed instantly every time the block is called and not after the iteration is over' (ruby-doc.org/core-1.9.3/Array.html#method-i-reject) so this is equivalent to modifying the array during iteration as I was doing. Maybe rows = rows.reject! { ... } would be better?
|
4

when using rails:

! rows.any?(&:present?)

Comments

2

You can use compact.uniq or compact. If your arrays have nil values, compact will result in an empty array, so you can check for that like this:

row.compact.size == 0

if row contains empty strings "" you can check for it like this:

row.compact.uniq.first.blank? and row.size == 1

Comments

0
    rows.select{|row| row.compact.count >0}

Comments

-1

Here: rows.all?(&:blank?).

1 Comment

He just wants to reject the array if ALL elements are empty.

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.