[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

code optimpization: delete_if, each, send.

dave

6/15/2005 8:42:00 AM



hi list,


i've a query string like inname:ruby,opt

the query is splitted in [ 'in', 'name', 'ruby', 'opt']

where 'in' is the name of a function (in-> true|false)
that look inside an hash for a key 'name' and returns true
if the value is 'ruby' || 'opt'.


hashes are in an array called list.
i would delete from the list array who doesn't match
the query.

-----------
list.delete_if(){
d = false
tokens.each {|t| # method, args, object
if (! d)
d = true if send(t[0].to_sym, t[1], t[2..-1])
end
b
}
}
---------------

is there a better way?

tnx.

--
>here are more things in heaven and earth,
horatio, than are dreamt of in your philosophy.


7 Answers

Robert Klemme

6/15/2005 11:17:00 AM

0

dave wrote:
> hi list,
>
>
> i've a query string like inname:ruby,opt
>
> the query is splitted in [ 'in', 'name', 'ruby', 'opt']
>
> where 'in' is the name of a function (in-> true|false)
> that look inside an hash for a key 'name' and returns true
> if the value is 'ruby' || 'opt'.
>
>
> hashes are in an array called list.
> i would delete from the list array who doesn't match
> the query.
>
> -----------
> list.delete_if(){
> d = false
> tokens.each {|t| # method, args, object
> if (! d)
> d = true if send(t[0].to_sym, t[1], t[2..-1])

You don't need to_sym - a string is ok.

Here you probably need a star - depending on the definition of the named
method.

> end
> b

'b' is undefined here. Is this a typo? Did you mean to write 'd'?

> }
> }
> ---------------
>
> is there a better way?

I'm not really sure what you're at. The first thing that confuses me is
that your outer block does not have a parameter. Normally you would have
the current hash as parameter there and would do some evaluation based on
this parameter. Other than that, you don't need the outer block at all -
your code just evaluates the same condition for each element in list.
This can be much simplified to:

tokens.any? {|meth, name, *args| send(meth, name, args)} and list.clear

If this doesn't help you please give a bit more information so we can
answer your question more appropriately.

Kind regards

robert

Devin Mullins

6/15/2005 12:30:00 PM

0

dave wrote:

> list.delete_if(){
> d = false
> tokens.each {|t| # method, args, object
> if (! d)
> d = true if send(t[0].to_sym, t[1], t[2..-1])
> end
> b
> }
> }
>
>is there a better way?
>
>
I assume you mean "shorter without being unreadable". Well, it's
subjective but...:

list.delete_if {
tokens.inject(false) {|d,t| # method, args, object
d ||= send(t[0], t[1], t[2..-1])
}
}

That's equivalent functionality, AFAICT, but I'm not sure what you're trying to do. delete_if() passes a parameter to your block (of each individual item). Here, the code will either do nothing, or clear the entire Array. Should the first line be
list.delete_if {|t|
?

Devin




dave

6/15/2005 7:22:00 PM

0



> delete_if() passes a parameter to your block

yes, sorry i'm very tired today :(

this code works and does what i need:
---------------
list.delete_if(){|obj| # the list is an array of objects
delete = false # delete the obj from the list
@tokens.each{|t| # tockens is the splitted query
if (! delete)
#
# func_signs is an hash.
# keys are regexp. values are functions name.
# if a token matches the regexp we pass it to
# the matched funtion value.
#
@func_signs.each_key(){|k|
if (t =~ k)
# the calles function split the tocken and
# return true if the obj satisfies this part of tocken
delete = (! send(@func_signs[k], obj, t))
end
}
end
}
delete
}
-----------------


examples:

query = 'inowner:dave'

matches /in(.+)/ => 'in' in func_signs hash.

if object.owner != 'dave' we must delete this object from the list.


i also would add support for or, not operators, ().
but this is another story :)


tnx, bie.


--
>here are more things in heaven and earth,
horatio, than are dreamt of in your philosophy.


Devin Mullins

6/16/2005 5:35:00 AM

0

dave wrote:

>list.delete_if(){|obj| # the list is an array of objects
> delete = false # delete the obj from the list
> @tokens.each{|t| # tockens is the splitted query
> if (! delete)
> @func_signs.each_key(){|k|
> if (t =~ k)
> # the calles function split the tocken and
> # return true if the obj satisfies this part of tocken
> delete = (! send(@func_signs[k], obj, t))
> end
> }
> end
> }
> delete
>}
>
>
I didn't test this, so don't assume it works...

list.delete_if{|obj|
@tokens.any? {|t|
@func_signs.any? {|k,v|
(t =~ k) && (!send(v, obj, t))
}
}
}

Not sure if that was what you were looking for...

Questions?

Actually, I've got one. If you do,
@func_signs.any? {|kv|
...
}

Ruby knows to pass the key and value as a single argument - the Array
[k,v] - instead of as the two arguments k and v. How? Can I write my own
code to do the same?

Devin



Robert Klemme

6/16/2005 10:01:00 AM

0

Devin Mullins wrote:
> dave wrote:
>
>> list.delete_if(){|obj| # the list is an array of objects
>> delete = false # delete the obj from the list
>> @tokens.each{|t| # tockens is the splitted query
>> if (! delete)
>> @func_signs.each_key(){|k|
>> if (t =~ k)
>> # the calles function split the tocken and
>> # return true if the obj satisfies this part of tocken
>> delete = (! send(@func_signs[k], obj, t))
>> end
>> }
>> end
>> }
>> delete
>> }
>>
>>
> I didn't test this, so don't assume it works...
>
> list.delete_if{|obj|
> @tokens.any? {|t|
> @func_signs.any? {|k,v|
> (t =~ k) && (!send(v, obj, t))
> }
> }
> }

I think that's as good as it can get with the current knowledge.
Depending on the distribution of data in @tokens and @func_signs one might
want to reorder the nesting to reduce the overall number of operations but
other than that this seems quite optimal.

> Not sure if that was what you were looking for...
>
> Questions?
>
> Actually, I've got one. If you do,
> @func_signs.any? {|kv|
> ...
> }
>
> Ruby knows to pass the key and value as a single argument - the Array
> [k,v] - instead of as the two arguments k and v. How? Can I write my
> own code to do the same?

>> def test() yield [1,2] end
=> nil
>> test {|a| p a}
[1, 2]
=> nil
>> test {|a,b| p a, b}
1
2
=> nil

Kind regards

robert

dave

6/16/2005 11:38:00 AM

0



> I didn't test this, so don't assume it works...
It does !

thank you.

--
>here are more things in heaven and earth,
horatio, than are dreamt of in your philosophy.


Devin Mullins

6/16/2005 1:42:00 PM

0

Interesting. It's a good thing matz is trying to wave off that "least
surprise" quote, because it was not least-suprising to me that blocks
would take parameters differently than methods. Now that I'm looking in
the pickaxe, though, I see a nice big section on parallel assignment
that explains what's happening.

Having fun with the roller-coaster ride that is Ruby... :)

Thanks,
Devin

Robert Klemme wrote:

>[1, 2]
>=> nil
>
>
>>>test {|a,b| p a, b}
>>>
>>>
>1
>2
>=> nil
>
>Kind regards
>
> robert
>
>
>
>
>