0

I am trying build a sentence out of 3 arrays with the count of each array.

cats = Cat.all 
dogs = Dog.all
birds = Bird.all 

animals = ["#{cats.count} Cats", "#{dogs.count} Dogs", "#{birds.count} Birds"]

sentence = animals.each.map{ |r| r  }.join(",  ") 

Right now, this works, but if I have no cats sentence outputs to

"O Cats, 5 Dogs, 4 Birds"

and I'ld like it to just say:

"5 Dogs & 4 Birds"

or, at the very least:

"5 Dogs, 4 Birds"

I feel like I might need to use an array of hashes, but I'm a bit lost.

1
  • something simpler is to declare your animals array empty like animals = [], and then add elements one by one like: animals << "#{cats.count} Cats" if cats.count > 0. It all depends on how your implementation is done, so, this might work or not for you. Commented Oct 5, 2016 at 21:42

2 Answers 2

3

Yes, you need a hash.

cats = Cat.all 
dogs = Dog.all
birds = Bird.all

animals = {
  cats: cats.count,
  dogs: dogs.count,
  birds: birds.count
}

sentence = animals.reject{|k, v| v.zero?}
                  .map{|k, v| "#{v} #{k.to_s.capitalize}"}
                  .join(', ')

My suggestion: keep data as data till the last moment, so that you can have maximum flexibility to display it in various ways. I feel that the animals in your code thinks rendering too soon.

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

4 Comments

FYI: [Cat, Bird, Dog].map { |c| [c.class.name.pluralize, c.count].select { |a,b| b > 0 }.map(&:join).join(","). This is overly clever but parts of it are definitely worth employing to shorten the creation of the hash.
perhaps use zero? here.
@sagarpandya82 Oh I didn't know that there's the method Numeric#zero?. It does make the code a bit cleaner. Thanks.
@meagar That's an interesting one liner. I didn't do this because I thought maybe the local variable cats and dogs and birds have other uses in OP's program.
2

To get "5 Dogs, 4 Birds", you can do

sentence = animals.each.map{ |r| /^0\s/.match(r) ? nil : r  }.compact.join(", ") 

The regex matches anything that starts with 0 and a space. If there is a match, return nil, or return the original string. The compact method removes nil elements from the array, and finally you join the elements.

If you want 5 Dogs & 4 Birds, you can define a method that performs that function.

def english_join(array)
  return array.to_s if array.nil? or array.length <= 1
  array[0..-2].join(", ") + " & " + array[-1]
end 

Then you can do

sentence = english_join(animals.each.map{ |r| /^0\s/.match(r) ? nil : r  }.compact)

If you have 0 cats, 5 dogs, and 4 birds, this returns 5 Dogs & 4 Birds.

If you have 2 cats, 5 dogs, and 4 birds, this returns 2 Cats, 5 Dogs & 4 Birds

1 Comment

I'm torn between these two answers. As you are both right. Plus your english join is right on.

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.