Hi everyone,
I want to create a query based on options passed in through
an options hash to my method.
The query would look like
"title:ruby and author:dave and publisher:oreilly"
or
"title:ruby and publisher:addison-wesley"
or
"author:dave"
or some other combination based on what options have been set in the hash.
options[:author] |= "" followed by Array#join doesn't help me
because it would lead to successive 'and's in the query.
"Gavri Fernandez" <gavri.fernandez@gmail.com> schrieb im Newsbeitrag news:e3ecfac705021308253ae8704e@mail.gmail.com...
Hi everyone,
I want to create a query based on options passed in through
an options hash to my method.
The query would look like
"title:ruby and author:dave and publisher:oreilly"
or
"title:ruby and publisher:addison-wesley"
or
"author:dave"
or some other combination based on what options have been set in the hash.
options[:author] |= "" followed by Array#join doesn't help me
because it would lead to successive 'and's in the query.
This is the solution I hit upon right after I sent my mail. Please
critique while I try to understand your solutions
def get_query(options)
query_fragments =
options.each do |key, value|
query_fragments.push("#{key.id2name}:#{value}")
end
query = query_fragments.join(" and ")
end
Thanks Robert
···
On Mon, 14 Feb 2005 01:44:57 +0900, Robert Klemme <bob.news@gmx.net> wrote:
"Gavri Fernandez" <gavri.fernandez@gmail.com> schrieb im Newsbeitrag
news:e3ecfac705021308253ae8704e@mail.gmail.com...
Here's a more efficient variant - using #inject of course
>> opts.inject(nil){|s,(k,v)| v ? (s ? s << " and " : "") << k << "=" << >> v :
>> s}
=> "title=ruby and author=dave and publisher=oreilly"
This is the solution I hit upon right after I sent my mail. Please
critique while I try to understand your solutions
def get_query(options)
query_fragments =
options.each do |key, value|
query_fragments.push("#{key.id2name}:#{value}")
end
query = query_fragments.join(" and ")
end
I'm missing the condition. As far as I understood you you want to be able to skip nil values. Did I get this wrong? Apart from that it does certainly what you want. If you want to spare the intermediate array you can do a bit optimization:
def get_query(options)
q = nil
options.each do |k,v|
q = (q ? q << " and " : "") << k << ":" << v
end
q
end
This is basically a verbose variant of my inject version.
Thanks Robert
You're welcome!
Kind regards
robert
···
On Mon, 14 Feb 2005 01:44:57 +0900, Robert Klemme <bob.news@gmx.net> > wrote:
opts.inject(nil) do |s,(k,v)|
if v
(s ? s << " and " : "") <<
(Enumerable === v && ! (String === v) ?
v.inject(nil) {|s2,v2| (s2 ? s2 << " or " : "(") << k << ":" << v2} << ")" :
"#{k}:#{v}")
else
s
end
end
Slightly unreadable... :-)) You don't need the outer if-else-end though if v is never nil.
Kind regards
robert
···
On Feb 13, 2005, at 11:44 AM, Robert Klemme wrote:
Robert Klemme wrote:
>
> Here's a more efficient variant - using #inject of course
>
> >> opts.inject(nil){|s,(k,v)| v ? (s ? s << " and " : "") << k <<
"="
<< v :
> >> s}
> => "title=ruby and author=dave and publisher=oreilly"
I prefer this:
opts.to_a.map{|x| x.join('=') if x[1]}.compact.join(' and ')
----> "title=ruby and author=dave and publisher=oreilly"
Too prolix. Better:
opts.map{|x| x.join('=') if x[1]}.compact.join(' and ')
Here are the stages through which the data travels:
{"title"=>"ruby", "author"=>"dave", "foo"=>nil, "publisher"=>"oreilly"}
["title=ruby", "author=dave", nil, "publisher=oreilly"]
["title=ruby", "author=dave", "publisher=oreilly"]
"title=ruby and author=dave and publisher=oreilly"
My bad. My mail was cluttered with
1) The problem
2) Possible solution by handling unused options by not considering them.
3) Possible solution by setting unused options as nil and handling
them while "joining"
Anyway, thanks for the solutions.
···
On Mon, 14 Feb 2005 02:35:02 +0900, Robert Klemme <bob.news@gmx.net> wrote:
I'm missing the condition. As far as I understood you you want to be able
to skip nil values. Did I get this wrong? Apart from that it does