# !x.include? y

**URL:** <https://www.ruby-forum.com/t/x-include-y/74071>\
**Category:** Ruby\
**Created:** [October 29, 2006, 7:03pm UTC](https://www.ruby-forum.com/t/x-include-y/74071 "2006-10-29T19:03:28Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [October 29, 2006, 7:03pm UTC](https://www.ruby-forum.com/t/x-include-y/74071/1 "2006-10-29T19:03:28Z")

</div>

basically, I need to filter list A to match list B. list A is a list  
of objects with a particular field, and list B is a list of acceptable  
values for that field.

what I have works but it reads sort of clumsily. I changed the ! to a  
not and got something slightly more readable:

list.reject! {|thing| not list\_of\_acceptable\_values.include?  
thing.attribute}

is there a nicer way to do it?

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [October 29, 2006, 7:41pm UTC](https://www.ruby-forum.com/t/x-include-y/74071/2 "2006-10-29T19:41:34Z")

</div>

Giles B. wrote:

> list.reject! {|thing| not list\_of\_acceptable\_values.include?  
> thing.attribute}
> 
> is there a nicer way to do it?

list.select {|thing| list\_of\_acceptable\_values.include? thing.attribute  
} ??

But then you need to reassign list, since I don’t know of any select!

```
Vince
```

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [October 29, 2006, 7:51pm UTC](https://www.ruby-forum.com/t/x-include-y/74071/3 "2006-10-29T19:51:35Z")

</div>

Hi –

On Mon, 30 Oct 2006, Vincent F. wrote:

> But then you need to reassign list, since I don’t know of any select!  
> This would be a nice use for delete\_unless.

David

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [October 29, 2006, 8:15pm UTC](https://www.ruby-forum.com/t/x-include-y/74071/4 "2006-10-29T20:15:40Z")

</div>

On 29/10/06, Giles B. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> …  
> list.reject! {|thing| not list\_of\_acceptable\_values.include? thing.attribute}
> 
> is there a nicer way to do it?

You could modify the Array class to include an accept! method that  
does the opposite of reject! (I’m sure someone else will chime in if  
this is wrong or bad practise!)

class Array  
def accept!  
delete\_if {|item| not yield item}  
end  
end

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 7, 2006, 10:47am UTC](https://www.ruby-forum.com/t/x-include-y/74071/5 "2006-11-07T10:47:06Z")

</div>

> def accept!  
> delete\_if {|item| not yield item}  
> end  
> end

this is a very tempting solution. a filter method could be cool too.

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 7, 2006, 10:47am UTC](https://www.ruby-forum.com/t/x-include-y/74071/6 "2006-11-07T10:47:05Z")

</div>

On 10/29/06, removed\_email\_address@domain.invalid [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > list.select {|thing| list\_of\_acceptable\_values.include? thing.attribute  
> > } ??
> > 
> > But then you need to reassign list, since I don’t know of any select!
> 
> This would be a nice use for delete\_unless.

Cheers, I didn’t know about delete\_unless. (I did find delete\_if.)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 7, 2006, 10:49am UTC](https://www.ruby-forum.com/t/x-include-y/74071/7 "2006-11-07T10:49:41Z")

</div>

Giles B. wrote:

> basically, I need to filter list A to match list B. list A is a list  
> of objects with a particular field, and list B is a list of acceptable  
> values for that field.

Interesting; you’re basically talking about set intersection:  
irb(main):001:0\> requested = %w|a b c x z|  
=\> [“a”, “b”, “c”, “x”, “z”]  
irb(main):002:0\> legal = %w|a b c d e f g|  
=\> [“a”, “b”, “c”, “d”, “e”, “f”, “g”]  
irb(main):003:0\> requested & legal  
=\> [“a”, “b”, “c”]

Except that you’re talking about calling considering an object  
equivalent to the value of one of its ‘fields’. I had hoped that the  
following would work, but no luck:  
class Object  
def equiv; self; end  
end

class Equiv  
def self.[]( data, equiv )  
self.new( data, equiv )  
end  
attr\_accessor :data, :equiv  
def initialize( data, equiv )  
@data, @equiv = data, equiv  
end  
def \<=\>( o2 ); @equiv \<=\> o2.equiv; end  
def == ( o2 ); @equiv == o2.equiv; end  
def ===( o2 ); @equiv === o2.equiv; end  
def eq?( o2 ); @equiv.eq?( o2.equiv ); end  
def hash; @equiv.hash end  
end

possible = [  
Equiv[1001, ‘a’],  
Equiv[1002, ‘b’],  
Equiv[1003, ‘c’],  
Equiv[2098, ‘x’],  
Equiv[3143, ‘z’]  
]  
legal = %w|a b c d e f g|

p possible & legal  
#=\> []

Looking at the source code for Array#&, I see that it uses the hash  
value of at least one of the arrays. (And I can see that my custom hash  
method above is getting called.) But that’s not enough. Apparently I  
can’t even _read_ C code any more, much less write it.

Can someone who is more C savvy than I am tell me what the following  
code is doing (and thus what might be done, if anything, to allow the  
built-in Array#& to work with custom classes pretending to be something  
they aren’t)?

static VALUE  
rb\_ary\_and(ary1, ary2)  
VALUE ary1, ary2;  
{  
VALUE hash, ary3, v, vv;  
long i;

```
ary2 = to_ary(ary2);
ary3 = rb_ary_new2(RARRAY(ary1)->len < RARRAY(ary2)->len ?
    RARRAY(ary1)->len : RARRAY(ary2)->len);
hash = ary_make_hash(ary2, 0);

for (i=0; i<RARRAY(ary1)->len; i++) {
v = vv = rb_ary_elt(ary1, i);
if (st_delete(RHASH(hash)->tbl, (st_data_t*)&vv, 0)) {
    rb_ary_push(ary3, v);
}
}

return ary3;

```

}

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 7, 2006, 10:49am UTC](https://www.ruby-forum.com/t/x-include-y/74071/8 "2006-11-07T10:49:16Z")

</div>

I like to modifiy Proc for making definining methods like this easier:

```
class Proc
  def inverse
    self.class.new {|*args| !self.call(*args)}
  end
end

```

Then of course you could continue down the path Marcel was suggesting:

```
class Array
  def select!(&block)
    delete_if &block.inverse
  end
  alias_method :find_all!, :select!
end

class Hash
  def select!(&block)
    delete_if &block.inverse
  end
  alias_method :find_all!, :select!
end

```

Actually, now this makes me want to think about what other kind of  
higher order goodies could be added to Proc =)

---

<div class="post-metadata">

**Author:** ![Giles\_B](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/g/848f3c/32.png) [@Giles\_B](https://www.ruby-forum.com/u/Giles_B)\
**Post date:** [November 7, 2006, 10:52am UTC](https://www.ruby-forum.com/t/x-include-y/74071/9 "2006-11-07T10:52:43Z")

</div>

Phrogz wrote:

> I had hoped that the following would work, but no luck:  
> [snip]

The reason that what I posted didn’t work is because I mispelled ‘eql?’  
as ‘eq?’. Oops. Following is code that does actually work:  
class Object  
def equiv; self; end  
end

class Equiv  
def self.[]( data, equiv )  
self.new( data, equiv )  
end  
attr\_accessor :data, :equiv  
def initialize( data, equiv )  
@data, @equiv = data, equiv  
end  
def \<=\>( o2 ); @equiv \<=\> o2.equiv end  
def == ( o2 ); @equiv == o2.equiv end  
def ===( o2 ); @equiv === o2.equiv end  
def eql?( o2 ); @equiv.eql?( o2.equiv ) end  
def hash; @equiv.hash end  
end

possible = [  
Equiv[1001, ‘a’],  
Equiv[1002, ‘b’],  
Equiv[1003, ‘c’],  
Equiv[2098, ‘x’],  
Equiv[3143, ‘z’]  
]  
legal = %w|a b c d e f g|

p possible & legal  
#=\> [#\<Equiv:0x283203c @equiv=“a”, @data=1001\>, #\<Equiv:0x2832000  
@equiv=“b”, @data=1002\>, #\<Equiv:0x2831fc4 @equiv=“c”, @data=1003\>]

So, going back to the original problem (which has long since been  
solved), we can do this instead:

require ‘equiv’  
objs\_as\_attributes = list.map{ |obj| Equiv[obj, obj.attribute] }  
acceptable\_obj\_wrappers = objs\_as\_attributes &  
list\_of\_acceptable\_values  
acceptable\_objs = acceptable\_obj\_wrappers.map{ |eq| eq.data }

Obviously that’s too much work. I smell an interesting approach for  
automatically treating one type of object as another:

module Enumerable  
def treat\_as( method )  
result = yield map{|obj| Equiv[obj, obj.send(method)]}  
if result.is\_a? Equiv  
result.data  
else  
result.map{ |obj| obj.is\_a?( Equiv ) ? obj.data : obj }  
end  
end  
end

Person = Struct.new( :name, :age )  
people = [  
Person.new( ‘Gavin’, 33 ),  
Person.new( ‘Bob’, 35 ),  
Person.new( ‘Jim’, 40 ),  
Person.new( ‘Lisa’, 32 ),  
Person.new( ‘Sam’, 30 )  
]

legal\_ages = [32, 33]  
legal\_people = people.treat\_as( :age ){ |people\_as\_ages|  
people\_as\_ages & legal\_ages  
}  
p legal\_people  
#=\> [#\<struct Person name=“Gavin”, age=33\>, #\<struct Person  
name=“Lisa”, age=32\>]

oldest = people.treat\_as( :age ){ |people\_as\_ages| people\_as\_ages.max  
}  
p oldest  
#=\> #\<struct Person name=“Jim”, age=40\>

This smells wrong applying only to Enumerables, but I’m too busy to  
really think this through. Just thought I’d share the idea.
