Gavin Kistner
10/31/2006 6:26:00 PM
Giles Bowkett 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;
}