Jones
Jones

Reputation: 1214

Ruby get strings from array which contain substring

I've got an array of strings. A few of the strings in this array contain a certain substring I'm looking for. I want to get an array of those strings containing the substring.

I would hope to do it like this:

a = ["abc", "def", "ghi"]
o.select(&:include?("c"))

But that gives me this error:

(repl):2: syntax error, unexpected ')', expecting end-of-input
o.select(&:include?("c"))
                        ^

Upvotes: 0

Views: 3516

Answers (3)

D-side
D-side

Reputation: 9485

You can use the &-shorthand here. It's rather irrational (don't do this), but possible.

If you do manage to find an object and a method so you can make checks in your select like so:

o.select { |e| some_object.some_method(e) }

(the important part is that some_object and some_method need to be the same in all iterations)

...then you can use Object#method to get a block like that. It returns something that implements to_proc (a requirement for &-shorthand) and that proc, when called, calls some_method on some_object, forwarding its arguments to it. Kinda like:

o.m(a, b, c) # <=> o.method(:m).to_proc.call(a, b, c)

Here's how you use this with the &-shorthand:

collection.select(&some_object.method(:some_method))

In this particular case, /c/ and its method =~ do the job:

["abc", "def", "ghi"].select(&/c/.method(:=~))

Kinda verbose, readability is relatively bad.
Once again, don't do this here. But the trick can be helpful in other situations, particularly where the proc is passed in from the outside.


Note: you may have heard of this shorthand syntax in a pre-release of Ruby 2.7, which was, unfortunately, reverted and didn't make it to 2.7:

["abc", "def", "ghi"].select(&/c/.:=~)

Upvotes: 5

Stefan
Stefan

Reputation: 114188

If your array was a file lines.txt

abc
def
ghi

Then you would select the lines containing c with the grep command-line utility:

$ grep c lines.txt
abc

Ruby has adopted this as Enumerable#grep. You can pass a regular expression as the pattern and it returns the strings matching this pattern:

['abc', 'def', 'ghi'].grep(/c/)
#=> ["abc"]

More specifically, the result array contains all elements for which pattern === element is true:

/c/ === 'abc' #=> true
/c/ === 'def' #=> false
/c/ === 'ghi' #=> false

Upvotes: 5

Radix
Radix

Reputation: 2747

You are almost there, you cannot pass parameter in &:. You can do something like:

o.select{ |e| e.include? 'c' }

Upvotes: 2

Related Questions