!x.include? y

G

Giles Bowkett

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?
 
V

Vincent Fourmond

Giles said:
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
 
D

dblack

Hi --

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.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
M

Marcel Ward

...
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
 
G

Giles Bowkett

...
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

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

Phrogz

Phrogz said:
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.
 

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,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top