2

I am looping through the array self.sisters as below:

brothers_in_law = []
self.sisters&.each do |sister|
  brothers_in_law << sister.spouse (if !sister.spouse.nil?)
end

How can I write it in the ruby way and also in one line?

1
  • 2
    Your code is not syntactically legal. It is hard to say what a "more Ruby way" of writing it is, if it isn't even legal Ruby in the first place. Commented Aug 16, 2020 at 9:49

2 Answers 2

7

In ruby, a rule of thumb is: if you have an each loop that is used for anything other than simply iterating the elements, there is 99% chance there is a better method.

brothers_in_law = sisters.map(&:spouse).reject(&:nil?)
# or 
brothers_in_law = sisters.map(&:spouse).compact
# or in ruby 2.7+
brothers_in_law = sisters.filter_map(&:spouse)
Sign up to request clarification or add additional context in comments.

5 Comments

These examples intentionally ignore potential nilness of sisters.
Does that mean that this code will not work if sisters array is nil?
@Lax_Sam: it means that this nilness should be handled elsewhere. For example by doing sisters ||= [] before this line.
Can't I write it like this? brothers_in_law = self.sisters&.map(&:spouse).reject(&:nil?)
You can, but this will leave your brothers_in_law as nil if sisters is nil. Anyhow, the matter of this nil check is orthogonal to the one-line form of your loop.
3

Testing:

sister = OpenStruct.new(spouse: "1")
sister1 = OpenStruct.new(spouse: "2")
sister2 = OpenStruct.new(spouse: nil)
sisters = [sister, sister1, sister2, nil]
brothers_in_law = []
brothers_in_law.concat sisters.compact&.map(&:spouse).compact unless sisters.nil?
=> ["1", "2"]

The compact calls remove the nil values on both sisters and their spouses, so only the spouse objects that exist are returned.

6 Comments

Oh ok. Got it. if brothers_in_law array already exists then I can do this right? brothers_in_law + sisters.compact&.map(&:spouse).compact
Call concat so you don't create a multidimensional array and you can append to it multiple times: brothers_in_law.concat sisters.compact&.map(&:spouse).compact
Ok. Got it. One last doubt. After this line: brothers_in_law.concat sisters.compact&.map(&:spouse).compact in the method if I should return brothers_in_law then should I write brothers_in_law after the above line or is the above line enough to return the array?
The oneliner will be enough to return the array
@benjessop: your code too does not expect sisters to be nil.
|

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.