42

This is a common, repetitive idiom for me: filtering an array using a regular expression, and returning a sub-array. My approach doesn't seem very Ruby-like (I come from Java). I end up having many methods which look a lot like this.

What is the idiomatic Ruby way to improve this code?

def get_all_gifs(items_)
  output = Array.new
  filter = /\.jpg$/
  items_.each do |item|
    next if item =~ filter
    output << item
  end
  output
end
2
  • How are you getting the filenames? If from disk you can filter them when you retrieve the names using Dir.glob('*.jpe?g') Commented Jun 27, 2013 at 23:43
  • I think almost everybody misunderstood my question (perhaps because I asked it badly). The example may be too loaded. This isn't about images or filenames or file extensions. It's about filtering of arrays, and a better idiom for methods to do that. Commented Jun 28, 2013 at 15:12

6 Answers 6

79

If you want to find all gifs:

def get_all_gifs(files)
  files.select{ |i| i[/\.gif$/] }
end

If you want to find all jpegs:

def get_all_jpgs(files)
  files.select{ |i| i[/\.jpe?g$/] }
end

Running them:

files = %w[foo.gif bar.jpg foo.jpeg bar.gif]
get_all_gifs(files) # => ["foo.gif", "bar.gif"]
get_all_jpgs(files) # => ["bar.jpg", "foo.jpeg"]

But wait! There's more!

What if you want to group them all by their type, then extract based on the extension?:

def get_all_images_by_type(files)
  files.group_by{ |f| File.extname(f) }
end

Here's the types of files:

get_all_images_by_type(files).keys # => [".gif", ".jpg", ".jpeg"]

Here's how to grab specific types:

get_all_images_by_type(files) # => {".gif"=>["foo.gif", "bar.gif"], ".jpg"=>["bar.jpg"], ".jpeg"=>["foo.jpeg"]}
get_all_images_by_type(files)['.gif'] # => ["foo.gif", "bar.gif"]
get_all_images_by_type(files).values_at('.jpg', '.jpeg') # => [["bar.jpg"], ["foo.jpeg"]]
Sign up to request clarification or add additional context in comments.

Comments

25

Have a look at Enumerable.grep, it's a very powerful way of finding/filtering things in anything enumerable.

2 Comments

This works like the dickens. I'll probably use this from now on, but in a narrow sense, the "select" method is what I was after in this question. Thanks very much.
Yes, grep is great, in part because it uses === to compare elements of the receiver to grep's argument. That allows you to write, for example, ["abc", "bcd", "cbd"].grep(/.b./) #=> ["abc", "cbd"] and [{a:1}, 4, {b:2}, "hat"].grep(Hash) #=> [{:a=>1}, {:b=>2}].
16
$ cat foo.rb
images = %w[foo.gif foo.png foo.jpg bar.jpeg moo.JPG]
jpgs = images.select{|e| e =~ /\.jpe?g$/i}
puts jpgs.inspect

$ ruby foo.rb
["foo.jpg", "bar.jpeg", "moo.JPG"]

The change to your regexp is so that you can match "jpeg" in addition to "jpg" regardless of case.

1 Comment

The "select" method is what I'm looking for here (or rather the "reject" method, now that I've found it). Thanks.
14
images = %w[foo.gif foo.png foo.jpg bar.jpeg moo.JPG]
images.grep(/.jpg/i) # => ["foo.jpg", "moo.JPG"]

1 Comment

oh come on Ruby sodlib team, we couldn't just call that .match also??
5

We can go without regex for this specific problem. Use String#end_with?

images = %w[foo.gif foo.png foo.jpg bar.jpeg moo.JPG]
images.find_all{|e| e.end_with?(".jpg",".jpeg")}
# => ["foo.jpg", "bar.jpeg"]

Comments

1
ta, tb = files.partition{|f| f[/(.*\.jpe*g)/]}

ap ta
[
    [0] "bar.jpg",
    [1] "foo.jpeg"
]


ap tb
[
    [0] "foo.gif",
    [1] "bar.gif"
]

/gucio

Comments

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.