[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

how to dynamically create search term for array.find_all

Adam Akhtar

4/6/2009 1:14:00 AM

i want to be able to create a mehtod that will filter results in an
array. The conditions are known at run time so id like to be able to do
it on the fly / dynamically.

e.g. user wants to filter results in array so that only results which
have the following categories are returned

:scifi
:comedy
:horror

id like that to be placed into a Array.find_all call like below


some_array.find_by {|x| x.category == :scifi OR x.category == :horror OR
x.category == :comedy}

how do i write the {....} bit if i dont know in advance exactly how many
/ which cateogries will be requested?

I know i could take hte users selections and put them in an array and do
this

filtered_results = []

users_filter_choices.each do |filter|
filtered_results += all_results.find_all{|x| x.category == filter
end

i dont know but is that bad for performance?
Also it assumes that the conditions must == , what happens if i want
less than or more thans in there for numerical attributes?
--
Posted via http://www.ruby-....

12 Answers

Phlip

4/6/2009 1:30:00 AM

0

Adam Akhtar wrote:

> i want to be able to create a mehtod that will filter results in an
> array. The conditions are known at run time so id like to be able to do
> it on the fly / dynamically.

In general, why not use ActiveRecord and sqlite3? Maybe you have other reasons
to use it, and dynamic queries is what AR's find system is all about...

> some_array.find_by {|x| x.category == :scifi OR x.category == :horror OR
> x.category == :comedy }

There's a very important principle in programming: After you write a unit test
for a feature (you _are_ writing unit tests, aren't you?), and after you add the
feature and pass the test, you then refactor to remove duplication, and make the
code more DRY.

When code obeys "Don't Repeat Yourself", it becomes easier to upgrade. For
example, if you had first merged all the duplicate .category == codes, you would
get this:

cats = [:scifi, :horror, :comedy]
some_array.find_by {|x| cats.include?(x.category) }

And that's your fix - change cats. This example shows how DRY code is easer to
extend and upgrade. This is counterintuitive, but I have yet to see a
counterexample.

Robert Klemme

4/6/2009 8:11:00 AM

0

On 06.04.2009 03:13, Adam Akhtar wrote:
> i want to be able to create a mehtod that will filter results in an
> array. The conditions are known at run time so id like to be able to do
> it on the fly / dynamically.
>
> e.g. user wants to filter results in array so that only results which
> have the following categories are returned
>
> :scifi
> :comedy
> :horror
>
> id like that to be placed into a Array.find_all call like below
>
>
> some_array.find_by {|x| x.category == :scifi OR x.category == :horror OR
> x.category == :comedy}
>
> how do i write the {....} bit if i dont know in advance exactly how many
> / which cateogries will be requested?
>
> I know i could take hte users selections and put them in an array and do
> this
>
> filtered_results = []
>
> users_filter_choices.each do |filter|
> filtered_results += all_results.find_all{|x| x.category == filter
> end
>
> i dont know but is that bad for performance?

Could be because you traverse the array multiple times. IMHO it is
generally better to do that only once, e.g.

require 'set'
ufc = users_filter_choices.to_set
all_results.find_all {|x| ufc.include?( x.category )}

> Also it assumes that the conditions must == , what happens if i want
> less than or more thans in there for numerical attributes?

It really depends on the condition. I mean you not only have to define
numbers but also which relation you want to evaluate.

Cheers

robert

Adam Akhtar

4/6/2009 10:22:00 AM

0

Thanks for your advice.

I like the use of include? in

cats = [:scifi, :horror, :comedy]
some_array.find_by {|x| cats.include?(x.category) }


to achieve what i wanted.

Nice tip!

thank you very much!

--
Posted via http://www.ruby-....

Adam Akhtar

4/6/2009 10:29:00 AM

0

ahh robert, sorry i missed your reply there, i was looking at
unrefreshed page from earlier today.


Many thanks for your response too. Im going to use that tip above plus
the odd sprinkling of eval("") for the conditions.

i noticed you used to_set. Ive never used sets before. Is there a reason
why you chose that over a standard array?

--
Posted via http://www.ruby-....

Srijayanth Sridhar

4/6/2009 11:58:00 AM

0

[Note: parts of this message were removed to make it a legal post.]

Set is used primarily for membership testing and is thus great for lookup.
It also of course is good to eliminate duplicates thus preventing any
inefficiencies in your code.

Jayanth

On Mon, Apr 6, 2009 at 3:58 PM, Adam Akhtar <adamtemporary@gmail.com> wrote:

> ahh robert, sorry i missed your reply there, i was looking at
> unrefreshed page from earlier today.
>
>
> Many thanks for your response too. Im going to use that tip above plus
> the odd sprinkling of eval("") for the conditions.
>
> i noticed you used to_set. Ive never used sets before. Is there a reason
> why you chose that over a standard array?
>
> --
> Posted via http://www.ruby-....
>
>

Adam Akhtar

4/6/2009 1:16:00 PM

0

Thanks Jayanth. Ill have to read up more about sets then. They look like
they could come in handy for a few other things i need to write.

Many thanks

--
Posted via http://www.ruby-....

Robert Klemme

4/6/2009 2:06:00 PM

0

On 06.04.2009 12:28, Adam Akhtar wrote:
> ahh robert, sorry i missed your reply there, i was looking at
> unrefreshed page from earlier today.

No problem.

> Many thanks for your response too. Im going to use that tip above plus
> the odd sprinkling of eval("") for the conditions.

I am not sure I get why you want to use eval. I try to avoid whenever
possible. Why do you believe you need it?

> i noticed you used to_set. Ive never used sets before. Is there a reason
> why you chose that over a standard array?

Set has O(1) lookup (because it is backed by a hash table internally),
while an Array has O(1). Whether it makes a difference in practice
needs to be measured. But if your number of categories grows then it's
almost certainly more efficient then an Array.

Of course, if you get categories in an Array you pay the extra price for
the conversion. If you can avoid that by directly passing a Set to the
method then this would be better of course.

Kind regards

robert


--
remember.guy do |as, often| as.you_can - without end

Rick DeNatale

4/6/2009 3:14:00 PM

0

[Note: parts of this message were removed to make it a legal post.]

On Mon, Apr 6, 2009 at 10:09 AM, Robert Klemme
<shortcutter@googlemail.com>wrote:

> On 06.04.2009 12:28, Adam Akhtar wrote:
>
> i noticed you used to_set. Ive never used sets before. Is there a reason
>> why you chose that over a standard array?
>>
>
> Set has O(1) lookup (because it is backed by a hash table internally),
> while an Array has O(1).


I think you meant to say that Array lookup is O(n).

--
Rick DeNatale

Blog: http://talklikeaduck.denh...
Twitter: http://twitter.com/Ri...
WWR: http://www.workingwithrails.com/person/9021-ric...
LinkedIn: http://www.linkedin.com/in/ri...

Robert Klemme

4/6/2009 5:09:00 PM

0

On 06.04.2009 17:13, Rick DeNatale wrote:
> On Mon, Apr 6, 2009 at 10:09 AM, Robert Klemme
> <shortcutter@googlemail.com>wrote:
>
>> On 06.04.2009 12:28, Adam Akhtar wrote:
>>
>> i noticed you used to_set. Ive never used sets before. Is there a reason
>>> why you chose that over a standard array?
>>>
>> Set has O(1) lookup (because it is backed by a hash table internally),
>> while an Array has O(1).
>
> I think you meant to say that Array lookup is O(n).

Yes, exactly. Thank you for the correction!

Kind regards

robert

Adam Akhtar

4/7/2009 1:32:00 AM

0

Ahh sorry Robert re: eval - categories are only half of the problem. Im
also allowing the user to filter by max and min stuff too.

So depending on what filtering options a user has set Ill have a varying
number of conditions in my code.

So one time it could be results.find_all{|x| x.rating <= some_parameter
&& x.rating>= some_other_parameter && etc etc etc }

Since iterating over the array only once is best for performance I
thought it would be best to call find_all once and stuff all the
required conditions into it. This was where i was stumped on how ot do
that so i thought i could use eval

like so:

#conditions are collected from users choices and are stored in a hash
some_conditions = {:max_rating => 10, :min_rating => 2, :categories =>
[:horror, :scifi] }

def filter (some_films, some_conditions)

condition_string = []
condition_string.push "x.rating <= #{some_conditions[max_rating]}" if
some_conditions[max_rating]
condition_string.push "x.rating >= #{some_conditions[min_rating}" if
some_conditions[min_rating]

condition_string = condition_string.join(" && ")

filtered_results = some_films.find_all{|x| eval(condition_string)}

return filtered_results
end


The above code didnt filter by categories as its just for example
purposes but I was thinking of simply calling find_all again using the
code offered before rather than drafting up a complicated eval string
involving && and ||. Id love ot hear how i can better this code.


--
Posted via http://www.ruby-....