Using array.select with grep

M

Milo Thurston

Using irb I set up the following arrays:
arr1 => ["one", "two", "three"]
arr2
=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.
=> ["two", "three"]

But what I actually get is:
=> ["one", "two", "three"]

What is my error or misunderstanding here?

Before anyone asks, I'm not using the array intersecttion (arr1 & arr2)
because I am testing this expression prior to using it to find objects
in an array (arr1) where an object parameter is found in an array of
strings (arr2), e.g. to find all people from the array of people objects
whose first name is in a list of names:

arr1.select { |y| arr2.grep(y.string_of_interest) }

Although if there's a better way of doing that I'd be interested to
know.
 
S

Stefano Crocco

Using irb I set up the following arrays:
=> ["one", "two", "three"]

=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.

=> ["two", "three"]

But what I actually get is:
=> ["one", "two", "three"]

What is my error or misunderstanding here?

Before anyone asks, I'm not using the array intersecttion (arr1 & arr2)
because I am testing this expression prior to using it to find objects
in an array (arr1) where an object parameter is found in an array of
strings (arr2), e.g. to find all people from the array of people objects
whose first name is in a list of names:

arr1.select { |y| arr2.grep(y.string_of_interest) }

Although if there's a better way of doing that I'd be interested to
know.

Array#grep returns an array with the matches, which means it returns an empty
array, which evaluates to true, if there's no match. You can do what you want
with

arr1.select{|y| !arr2.grep(y).empty?}

I hope this helps

Stefano
 
S

Stefan Lang

2008/8/1 Milo Thurston said:
Using irb I set up the following arrays:
arr1 => ["one", "two", "three"]
arr2
=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.
=> ["two", "three"]

But what I actually get is:
=> ["one", "two", "three"]

What is my error or misunderstanding here?

Because grep returns an empty array when it can't find the
given string. And an empty array (everything except false and nil,
actually) is true in Ruby. Use #include? instead:

arr1.select { |y| arr2.include?(y) }

Stefan
 
D

David A. Black

Hi --

2008/8/1 Milo Thurston said:
Using irb I set up the following arrays:
arr1 => ["one", "two", "three"]
arr2
=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.
arr1.select { |y| arr2.grep(y) }
=> ["two", "three"]

But what I actually get is:
arr1.select { |y| arr2.grep(y) }
=> ["one", "two", "three"]

What is my error or misunderstanding here?

Because grep returns an empty array when it can't find the
given string. And an empty array (everything except false and nil,
actually) is true in Ruby. Use #include? instead:

arr1.select { |y| arr2.include?(y) }

No, that's not the same.
array = %w{ one two three } => ["one", "two", "three"]
array.grep(/e/) => ["one", "three"]
array.include?("e")
=> false


David
 
S

shadowfirebird

Someone please correct me if I'm barking up the wrong tree, but the
block in select wants a function that returns a logical, and grep
isn't one.

It seems to work if you use include?(), instead, though.

irb(main):004:0> a1 = [ "one", "two", "three" ]
=> ["one", "two", "three"]
irb(main):005:0> a2 = ["two", "three", "four" ]
=> ["two", "three", "four"]
irb(main):006:0> a1.find_all{|x| a2.grep(x)}
=> ["one", "two", "three"]
irb(main):007:0> a1.find_all{|x| a2.grep(x) == true}
=> []
irb(main):007:0> a1.find_all{|x| a2.include?(x)}
=> ["two", "three"]



Using irb I set up the following arrays:
arr1 => ["one", "two", "three"]
arr2
=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.
=> ["two", "three"]

But what I actually get is:
=> ["one", "two", "three"]

What is my error or misunderstanding here?

Before anyone asks, I'm not using the array intersecttion (arr1 & arr2)
because I am testing this expression prior to using it to find objects
in an array (arr1) where an object parameter is found in an array of
strings (arr2), e.g. to find all people from the array of people objects
whose first name is in a list of names:

arr1.select { |y| arr2.grep(y.string_of_interest) }

Although if there's a better way of doing that I'd be interested to
know.


--
Me, I imagine places that I have never seen / The colored lights in
fountains, blue and green / And I imagine places that I will never go
/ Behind these clouds that hang here dark and low
But it's there when I'm holding you / There when I'm sleeping too /
There when there's nothing left of me / Hanging out behind the
burned-out factories / Out of reach but leading me / Into the
beautiful sea
 
R

Robert Klemme

2008/8/1 Milo Thurston said:
Before anyone asks, I'm not using the array intersecttion (arr1 & arr2)
because I am testing this expression prior to using it to find objects
in an array (arr1) where an object parameter is found in an array of
strings (arr2), e.g. to find all people from the array of people objects
whose first name is in a list of names:

arr1.select { |y| arr2.grep(y.string_of_interest) }

Although if there's a better way of doing that I'd be interested to
know.

Just one additional remark: if your Arrays grow large you might
benefit from converting them to Set which has faster lookups.

Kind regards

robert
 
D

David A. Black

Hi --

Someone please correct me if I'm barking up the wrong tree, but the
block in select wants a function that returns a logical, and grep
isn't one.

It seems to work if you use include?(), instead, though.

irb(main):004:0> a1 = [ "one", "two", "three" ]
=> ["one", "two", "three"]
irb(main):005:0> a2 = ["two", "three", "four" ]
=> ["two", "three", "four"]
irb(main):006:0> a1.find_all{|x| a2.grep(x)}
=> ["one", "two", "three"]
irb(main):007:0> a1.find_all{|x| a2.grep(x) == true}
=> []
irb(main):007:0> a1.find_all{|x| a2.include?(x)}
=> ["two", "three"]

See my previous post. #grep and #include? are not the same.


David
 
S

Sebastian Hungerecker

David said:
No, that's not the same.

=> ["one", "two", "three"]

=> ["one", "three"]

array.grep("e")
=> []

So since the code in question only deals with strings and not regexen, using
include? does indeed have the same result as checking whether grep returned
an empty array.

HTH,
Sebastian
 
S

Stefano Crocco

Someone please correct me if I'm barking up the wrong tree, but the
block in select wants a function that returns a logical, and grep
isn't one.

Everything in ruby can be used as a boolean value, so technically you can use
it. The only problem is that the value grep returns is always a 'true' value.

Stefano
 
S

Stefan Lang

2008/8/1 David A. Black said:
Hi --

2008/8/1 Milo Thurston said:
Using irb I set up the following arrays:

arr1

=> ["one", "two", "three"]

arr2

=> ["two", "three", "four"]

I would expect to be able to collect the elements of arr1 that are also
in arr2 using select and grep, i.e.

arr1.select { |y| arr2.grep(y) }

=> ["two", "three"]

But what I actually get is:

arr1.select { |y| arr2.grep(y) }

=> ["one", "two", "three"]

What is my error or misunderstanding here?

Because grep returns an empty array when it can't find the
given string. And an empty array (everything except false and nil,
actually) is true in Ruby. Use #include? instead:

arr1.select { |y| arr2.include?(y) }

No, that's not the same.
=> ["one", "two", "three"]
=> ["one", "three"]
=> false

Given Milo's use case, he's only using strings, so it doesn't
matter. include? is clearer in this case, IMO.

Stefan
 
S

shadowfirebird

I didn't say they were the same; I said that grep() didn't work in
that context, but include?() did. :D

Everything in ruby can be used as a boolean value, so technically you can
use
it. The only problem is that the value grep returns is always a 'true'
value.

Stefano


--
Me, I imagine places that I have never seen / The colored lights in
fountains, blue and green / And I imagine places that I will never go
/ Behind these clouds that hang here dark and low
But it's there when I'm holding you / There when I'm sleeping too /
There when there's nothing left of me / Hanging out behind the
burned-out factories / Out of reach but leading me / Into the
beautiful sea
 
M

Milo Thurston

Robert said:
Just one additional remark: if your Arrays grow large you might
benefit from converting them to Set which has faster lookups.


You're right - if I use a Set then the lookup is astonishingly fast by
comparison.
Is it OK to combine arrays and sets, though? For example, I have a Set
of things I need to grep and an array I don't, and these need to be
combined as an array. So, is:

final = set + array

...OK, or do I need to do

final = set.to_a + array

...or even something else?
Thanks.
 
R

Robert Klemme

2008/8/1 Milo Thurston said:
You're right - if I use a Set then the lookup is astonishingly fast by
comparison.
Is it OK to combine arrays and sets, though? For example, I have a Set
of things I need to grep and an array I don't, and these need to be
combined as an array. So, is:

final = set + array

...OK, or do I need to do

final = set.to_a + array

...or even something else?

It all depends on what you need. If you need Set semantics, use Sets.
If you need lists (maintain a particular order) use Arrays. It all
depends. You can easily convert via #to_a and #to_set. But if you are
finding yourself converting all the time chances are that you are
doing something wrong. :)

Cheers

robert
 
D

David A. Black

Hi --

David said:
No, that's not the same.
array = %w{ one two three }

=> ["one", "two", "three"]
array.grep(/e/)

=> ["one", "three"]

array.grep("e")
=> []

So since the code in question only deals with strings and not regexen, using
include? does indeed have the same result as checking whether grep returned
an empty array.

Right -- I un-stringed them by mistake.


David
 
D

David A. Black

Hi --

I didn't say they were the same; I said that grep() didn't work in
that context, but include?() did. :D

I think that was in reply to me, and it's true that I was using "not
the same" to mean "not interchangeable" -- but in fact I was all wrong
anyway because I rewrote the OP's code in my head to use regexes
instead of strings.


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,020
Latest member
GenesisGai

Latest Threads

Top