Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > "Joining" strings which may be nil (or) Handling Option hashes

Reply
Thread Tools

"Joining" strings which may be nil (or) Handling Option hashes

 
 
Gavri Fernandez
Guest
Posts: n/a
 
      02-13-2005
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 publisherreilly"
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.

What is the Ruby Idiom to achieve what I want?

TIA
--
Gavri
---------------------------------------------------
I blog here: http://gavri.blogspot.com


 
Reply With Quote
 
 
 
 
Robert Klemme
Guest
Posts: n/a
 
      02-13-2005

"Gavri Fernandez" <> schrieb im Newsbeitrag
news:...
> 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 publisherreilly"
> 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.
>
> What is the Ruby Idiom to achieve what I want?


Lots of, here are some:

>> opts = {"title"=>"ruby", "author"=>"dave", "publisher"=>"oreilly",
>> "foo"=>nil}

=> {"title"=>"ruby", "author"=>"dave", "foo"=>nil, "publisher"=>"oreilly"}
>> opts.select{|k,v|v}

=> [["title", "ruby"], ["author", "dave"], ["publisher", "oreilly"]]
>> opts.select{|k,v|v}.map{|k,v| "#{k}=#{v}"}.join(" and ")

=> "title=ruby and author=dave and publisher=oreilly"

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"

Kind regards

robert

 
Reply With Quote
 
 
 
 
Francis Hwang
Guest
Posts: n/a
 
      02-13-2005
On Feb 13, 2005, at 11:44 AM, Robert Klemme wrote:
> Lots of, here are some:
>
>>> opts = {"title"=>"ruby", "author"=>"dave", "publisher"=>"oreilly",
>>> "foo"=>nil}

> => {"title"=>"ruby", "author"=>"dave", "foo"=>nil,
> "publisher"=>"oreilly"}
>>> opts.select{|k,v|v}

> => [["title", "ruby"], ["author", "dave"], ["publisher", "oreilly"]]
>>> opts.select{|k,v|v}.map{|k,v| "#{k}=#{v}"}.join(" and ")

> => "title=ruby and author=dave and publisher=oreilly"
>
> 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"


Maybe the OP isn't worried about this, but: Is there a way to represent
ORs as well as ANDs if you're doing this?

Francis Hwang
http://fhwang.net/



 
Reply With Quote
 
Gavri Fernandez
Guest
Posts: n/a
 
      02-13-2005
On Mon, 14 Feb 2005 01:44:57 +0900, Robert Klemme <> wrote:
>
> "Gavri Fernandez" <> schrieb im Newsbeitrag
> news:...


> Lots of, here are some:
>
> >> opts = {"title"=>"ruby", "author"=>"dave", "publisher"=>"oreilly",
> >> "foo"=>nil}

> => {"title"=>"ruby", "author"=>"dave", "foo"=>nil, "publisher"=>"oreilly"}
> >> opts.select{|k,v|v}

> => [["title", "ruby"], ["author", "dave"], ["publisher", "oreilly"]]
> >> opts.select{|k,v|v}.map{|k,v| "#{k}=#{v}"}.join(" and ")

> => "title=ruby and author=dave and publisher=oreilly"
>
> 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

Thanks Robert
--
Gavri
---------------------------------------------------
I blog here: http://gavri.blogspot.com


 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      02-13-2005

"Gavri Fernandez" <> schrieb im Newsbeitrag
news:...
> On Mon, 14 Feb 2005 01:44:57 +0900, Robert Klemme <>
> wrote:
>>
>> "Gavri Fernandez" <> schrieb im Newsbeitrag
>> news:...

>
>> Lots of, here are some:
>>
>> >> opts = {"title"=>"ruby", "author"=>"dave", "publisher"=>"oreilly",
>> >> "foo"=>nil}

>> => {"title"=>"ruby", "author"=>"dave", "foo"=>nil,
>> "publisher"=>"oreilly"}
>> >> opts.select{|k,v|v}

>> => [["title", "ruby"], ["author", "dave"], ["publisher", "oreilly"]]
>> >> opts.select{|k,v|v}.map{|k,v| "#{k}=#{v}"}.join(" and ")

>> => "title=ruby and author=dave and publisher=oreilly"
>>
>> 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

 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      02-13-2005

"Francis Hwang" <> schrieb im Newsbeitrag
news:.. .
> On Feb 13, 2005, at 11:44 AM, Robert Klemme wrote:
>> Lots of, here are some:
>>
>>>> opts = {"title"=>"ruby", "author"=>"dave", "publisher"=>"oreilly",
>>>> "foo"=>nil}

>> => {"title"=>"ruby", "author"=>"dave", "foo"=>nil,
>> "publisher"=>"oreilly"}
>>>> opts.select{|k,v|v}

>> => [["title", "ruby"], ["author", "dave"], ["publisher", "oreilly"]]
>>>> opts.select{|k,v|v}.map{|k,v| "#{k}=#{v}"}.join(" and ")

>> => "title=ruby and author=dave and publisher=oreilly"
>>
>> 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"

>
> Maybe the OP isn't worried about this, but: Is there a way to represent
> ORs as well as ANDs if you're doing this?


You could provide multiple values for a key and create an OR from that:

opts = {"title"=>["ruby","foobar"], "author"=>"dave"}

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

 
Reply With Quote
 
William James
Guest
Posts: n/a
 
      02-13-2005
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"

 
Reply With Quote
 
Gavri Fernandez
Guest
Posts: n/a
 
      02-14-2005
On Mon, 14 Feb 2005 02:35:02 +0900, Robert Klemme <> 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


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.


--
Gavri
---------------------------------------------------
I blog here: http://gavri.blogspot.com


 
Reply With Quote
 
William James
Guest
Posts: n/a
 
      02-15-2005

William James 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"

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Integer(nil) versus Float(nil) versus String(nil) Christoffer Sawicki Ruby 5 09-02-2006 06:28 PM
a == nil or a.nil? ako... Ruby 6 11-23-2005 05:03 AM
Hash of hashes, of hashes, of arrays of hashes Tim O'Donovan Perl Misc 5 10-28-2005 05:59 AM
RCR 303: nil should accept missing methods and return nil John Carter Ruby 64 05-19-2005 12:12 PM
puts nil generates "nil\n" Brian Candler Ruby 1 11-06-2004 01:59 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57