[QUIZ] Price Ranges (#164)

M

Matthew Moss

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

Apologies for the late quiz... been rather busy today. Here's another simple
one, but practical. I didn't get specific about input
formats/parameters/etc, I leave that to you this week.


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/<http://matthew.moss.googlepages.com/home>>.


3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Price Ranges

_Quiz description by James Edward Gray II_

You have a list of price ranges from different vendors like:

Company A: $1,000 - $3,000
Company B: $6,000 - $10,000
Company C: $500 - $2,500

Given such a list and the desired price range a shopper wishes to pay,
return the companies the shopper should examine. For example, if the
shopper's price range was:

Low: $2,500
High: $5,000

the companies returned would be:

Company A
Company C

The shopper should also be allowed to provide just a low or just a high
value instead of both, should they prefer to do so.
 
M

Matthew Moss

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

Why does typing a simple email have to be so difficult? *sheesh* The
correct, unmanged web address is:

<http://splatbang.com/rubyquiz/>
 
M

Matthew Moss

Why does typing a simple email have to be so difficult? *sheesh* The
correct, unmanged web address is:

Unmanged?

*smack head*

I swear, my I.Q. must be dropping 10 points _daily_.
 
R

Robert Dober

Unmanged?

*smack head*

I swear, my I.Q. must be dropping 10 points _daily_.
Cheer up Matt I am trying to put my gmail into TWI*M mode for years
now and I cannot figure out how. Hugh.
R.
 
C

Chris Shea

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

Apologies for the latequiz... been rather busy today. Here's another simple
one, but practical. I didn't get specific about input
formats/parameters/etc, I leave that to you this week.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of RubyQuiz2:

1. Please do not post any solutions or spoiler discussion for thisquizuntil 48 hours have passed from the time on this message.

2. Support RubyQuiz2 by submitting ideas as often as you can! (A
permanent, new website is in the works for RubyQuiz2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/<http://matthew.moss.googlepages.com/home>>.

3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the originalquizmessage, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Price Ranges

_Quiz description by James Edward Gray II_

You have a list of price ranges from different vendors like:

Company A: $1,000 - $3,000
Company B: $6,000 - $10,000
Company C: $500 - $2,500

Given such a list and the desired price range a shopper wishes to pay,
return the companies the shopper should examine. For example, if the
shopper's price range was:

Low: $2,500
High: $5,000

the companies returned would be:

Company A
Company C

The shopper should also be allowed to provide just a low or just a high
value instead of both, should they prefer to do so.

You weren't looking for a user interface, were you? ;)

http://pastie.textmate.org/207034

Chris
 
A

Andrea Fazzi

Matthew Moss ha scritto:
Apologies for the late quiz... been rather busy today. Here's another simple
one, but practical. I didn't get specific about input
formats/parameters/etc, I leave that to you this week.


-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Quiz 2:

1. Please do not post any solutions or spoiler discussion for this
quiz until 48 hours have passed from the time on this message.

2. Support Ruby Quiz 2 by submitting ideas as often as you can! (A
permanent, new website is in the works for Ruby Quiz 2. Until then,
please visit the temporary website at

<http://splatbang.com/rubyquiz/<http://matthew.moss.googlepages.com/home>>.


3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby Talk follow the discussion. Please reply to
the original quiz message, if you can.
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

## Price Ranges

_Quiz description by James Edward Gray II_

You have a list of price ranges from different vendors like:

Company A: $1,000 - $3,000
Company B: $6,000 - $10,000
Company C: $500 - $2,500

Given such a list and the desired price range a shopper wishes to pay,
return the companies the shopper should examine. For example, if the
shopper's price range was:

Low: $2,500
High: $5,000

the companies returned would be:

Company A
Company C

The shopper should also be allowed to provide just a low or just a high
value instead of both, should they prefer to do so.

Here my solution (with specs):

http://pastie.caboo.se/207093
http://pastie.caboo.se/207095

Bye.
Andrea
 
S

Steven Hahn

I had not created a SAX listener before in Ruby. So, my solution reads the=
vendor list in from XML. I noticed others were using this pastie thingy..=
I don't know what that is. Besides, pasties always seemed to be kind of =
pointless to me. They leave precious little to the imagination. So, below=
is the ruby file followed by the xml file:

---------------------------------------------------------------------------=
------
#!/usr/local/bin/ruby -w
require 'rexml/parsers/sax2parser'
require 'rexml/sax2listener'

class VendorListener
include REXML::SAX2Listener

def initialize(low, high)
begin
@low =3D Float(low)
rescue
@low =3D 0
end
=20
begin
@high =3D Float(high)
rescue
#if someone can spend more than this then
#they can afford a better program
@high =3D 10**15
end
end
=20
def start_element(uri, localname, tag_name, attrs)
if tag_name =3D=3D 'Vendor'
@vendorName =3D attrs['name']
end
end

def end_element(uri, localname, tag_name)
if tag_name =3D=3D 'Vendor'
if in_range?
puts @vendorName
end
elsif tag_name =3D=3D 'LowPrice'
@lowPrice =3D Float(@data)
elsif tag_name =3D=3D 'HighPrice'
@highPrice =3D Float(@data)
end
end

def characters(value)
@data =3D value
end

def in_range?
(@low >=3D @lowPrice and @low <=3D @highPrice) or
(@high >=3D @lowPrice and @high <=3D @highPrice) or
(@low < @lowPrice and @high > @highPrice)
end
end

puts "Enter a price range."
print "Enter low value: "
low =3D gets
print "Enter high value: "
high =3D gets

parser =3D REXML::parsers::SAX2Parser.new(File.new('vendors.xml' ))
parser.listen(VendorListener.new(low, high))
parser.parse

puts "Program terminated."
---------------------------------------------------------------------------=
------
<?xml version=3D"1.0" encoding=3D"UTF-8"?>
<Vendors>
<Vendor name=3D"Company A">
<PriceRange>
<LowPrice>1000</LowPrice>
<HighPrice>3000</HighPrice>
</PriceRange>
</Vendor>
<Vendor name=3D"Company B">
<PriceRange>
<LowPrice>6000</LowPrice>
<HighPrice>10000</HighPrice>
</PriceRange>
</Vendor>
<Vendor name=3D"Company C">
<PriceRange>
<LowPrice>500</LowPrice>
<HighPrice>2500</HighPrice>
</PriceRange>
</Vendor>
</Vendors>


_________________________________________________________________
Make every e-mail and IM count. Join the i=92m Initiative from Microsoft.
http://im.live.com/Messenger/IM/Join/Default.aspx?source=3DEML_WL_ MakeCoun=
t=
 
J

Jesús Gabriel y Galán

## Price Ranges

_Quiz description by James Edward Gray II_

You have a list of price ranges from different vendors like:

Company A: $1,000 - $3,000
Company B: $6,000 - $10,000
Company C: $500 - $2,500

Given such a list and the desired price range a shopper wishes to pay,
return the companies the shopper should examine. For example, if the
shopper's price range was:

Low: $2,500
High: $5,000

the companies returned would be:

Company A
Company C

The shopper should also be allowed to provide just a low or just a high
value instead of both, should they prefer to do so.

Here's my solution. I use codeforpeople's main, so the program accepts
a --help that explains the params. I expected a file in CSV format for
the company data:

company1, low, high
company2, low, high

and the shopper's low and high are passed as options to the program:

require 'main'
require 'fastercsv'

Main {
argument('file')

option('low', 'l') {
argument_required
cast :int
default 0
}

option('high', 'g') {
argument_required
cast :int
}

def run
file = params[:file].value
low = params[:low].value
have_high = params[:high].given?
high = params[:high].value if have_high
values = []
FasterCSV.foreach file do |line|
cmp_values = [line[0]]
cmp_values << line[1].to_i
cmp_values << line[2].to_i
values << cmp_values
end

unless have_high
companies = values.select {|x| x[2] >= low}
else
companies = values.reject {|x| (x[1] > high) || (x[2] < low)}
end
companies.map! {|x| x[0]}
puts companies
end
}

For example for this company_data.csv file:

company1, 1000, 3000
company2, 6000, 10000
company3, 500, 2500

these are some runs:

$ ruby quiz164.rb company_data.csv
company1
company2
company3

$ ruby quiz164.rb company_data.csv -l 4000
company2

$ ruby quiz164.rb company_data.csv -l 4000 -g 5000

$ ruby quiz164.rb company_data.csv -g 1500
company1
company3

$ ruby quiz164.rb company_data.csv -g 750
company3

$ ruby quiz164.rb --help
NAME
quiz164.rb

SYNOPSIS
quiz164.rb file [options]+

PARAMETERS
file (1 -> file)
--low=low, -l (0 ~> int(low=0))
--high=high, -g (0 ~> int(high))
--help, -h


Thanks for the quiz.

Jesus.
 
T

Toby O'Rourke

A simple solution to my first Ruby Quiz

class SupplierFinder
attr_accessor :companies
def initialize(suppliers='')
@companies = Hash.new
File.open(suppliers).each do |line|
range = line.scan(/\$[\d,]+/)
companies.store( Range::new(parse(range[0]),parse(range[1])),
line.match(/^[\w\s]*/))
end
end
def search(switch=nil, low=0, high=0)
my_range = Range::new(low, high) if switch == '-r'
companies.each_pair do |range, name|
puts name if ( !my_range.nil? and (my_range.include? range.first
or my_range.include? range.last or range.include? low or
range.include? high )) or (switch == '-h' and range.first <= low) or
(switch == '-l' and range.last >= low)
end
end
private
def parse(price)
price.gsub( '$', '').gsub(',','').to_i
end
end
SupplierFinder.new(ARGV[0]).search(ARGV[1], ARGV[2].to_i,
ARGV[3].to_i) if __FILE__ == $0

Cheers,

Toby.
 
H

Harry Kakueki

=begin

Here is my solution.
It accepts input like this:
2500_5000 #lower_upper
2500_ #lower only
_5000 #upper only

=end

min,max = ARGV[0].split(/_/)
a,b,c = (1000..3000).to_a,(6000..10000).to_a,(500..2500).to_a
l,u = min.to_i,max.to_i
u = [a,b,c].flatten.max if max == nil
l = 0 if min == ""
cust = (l..u).to_a
p "a" unless (cust & a).empty?
p "b" unless (cust & b).empty?
p "c" unless (cust & c).empty?

Harry
 
S

Steven Hahn

I hadn't planned on making another submission, but after tinkering with it =
a bit I realized a few things:

1. A simple GUI would be nice. I used FXRuby.
2. The SAX Listener was barfing when the number of vendors was six or more.=
Funny thing was that it only had a problem when the XML was formatted. I=
f I removed the whitespace it did just fine. In any case, I switched to us=
ing a StreamListener instead.
3. There was an inconsistency in the logic in my original in_range? method.

Anyway, here is the Ruby code followed by sample XML:
--------------------------------------------------------------
#!/usr/local/bin/ruby -w
require 'rexml/document'
require 'rexml/streamlistener'
require 'fox16'
include Fox

class VendorListener=20
include REXML::StreamListener
def initialize(low_price, high_price, vendor_search_window)
begin
@low_price =3D Float(low_price)
rescue
@low_price =3D 0
end
=20
begin
@high_price =3D Float(high_price)
rescue
#if someone can spend more than this then
#she or he can afford a better program
@high_price =3D 10**15
end
=20
@vdr_srch_wdw =3D vendor_search_window
end
=20
def tag_start(name, attrs)
if name =3D=3D 'Vendor'
@vendor_name =3D attrs['name']
end
end
=20
def tag_end(name)
if name =3D=3D 'Vendor' and=20
if in_range?
@vdr_srch_wdw.add_vendor(@vendor_name)
end
elsif name =3D=3D 'LowPrice'
@vendor_low_price =3D Float(@data)
elsif name =3D=3D 'HighPrice'
@vendor_high_price =3D Float(@data)
end
end

def text(text)
@data =3D text
end

def in_range?
@low_price <=3D @high_price and
(@low_price >=3D @vendor_low_price or @high_price >=3D @vendor_low_pr=
ice) and
(@low_price <=3D @vendor_high_price or @high_price <=3D @vendor_high_=
price)
end
end

class VendorSearchWindow < FXMainWindow
def initialize(app)
# Invoke base class initialize first
super(app, "Ruby Quiz \#164: Vendor Search", nil, nil, DECOR_TITLE | DE=
COR_CLOSE)

#Add text field frame at the top
textfields =3D FXHorizontalFrame.new(self, LAYOUT_SIDE_TOP|LAYOUT_CENTE=
R_X)
FXLabel.new(textfields, "Enter a range:", nil, JUSTIFY_LEFT)
FXLabel.new(textfields, "low:", nil, JUSTIFY_RIGHT)
@low_field =3D FXTextField.new(textfields, 10, nil, 0, JUSTIFY_RIGHT|FR=
AME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
FXLabel.new(textfields, "high:", nil, JUSTIFY_RIGHT)
@high_field =3D FXTextField.new(textfields, 10, nil, 0, JUSTIFY_RIGHT|F=
RAME_SUNKEN|FRAME_THICK|LAYOUT_SIDE_TOP)
=20
#add button frame at the bottom
buttons =3D FXHorizontalFrame.new(self, LAYOUT_SIDE_BOTTOM|LAYOUT_CENTE=
R_X|PACK_UNIFORM_WIDTH)
show_button =3D FXButton.new(buttons, "Show Vendors")
show_button.connect(SEL_COMMAND, method:)on_show_vendors))
exit_button =3D FXButton.new(buttons, "Exit")
exit_button.connect(SEL_COMMAND, method:)on_exit))

#Place the list in a sunken frame
sunken_frame =3D FXHorizontalFrame.new(self,
LAYOUT_FILL_X|LAYOUT_FILL_Y|FRAME_SUNKEN|FRAME_THICK, :padding =
=3D> 0)
@vendor_list =3D FXList.new(sunken_frame, :eek:pts =3D> LIST_SINGLESELECT|=
LAYOUT_FILL_X|LAYOUT_FILL_Y)
end

def on_exit(sender, sel, ptr)
getApp().exit
end
=20
def on_show_vendors(sender, sel, ptr)
@vendor_list.clearItems(false)
REXML::Document.parse_stream(File.new('vendors.xml' ),
VendorListener.new(@low_field.text, @high_field.text, self))
end
=20
def add_vendor(vndr_name)
@vendor_list.appendItem(vndr_name)
end
=20
def create
super
show(PLACEMENT_SCREEN)
end
end

application =3D FXApp.new
VendorSearchWindow.new(application)
application.create
application.run
--------------------------------------------------------------
<?xml version=3D"1.0" encoding=3D"UTF-8"?>
<Vendors>
<Vendor name=3D"Company A">
<PriceRange>
<LowPrice>1000</LowPrice>
<HighPrice>3000</HighPrice>
</PriceRange>
</Vendor>
<Vendor name=3D"Company B">
<PriceRange>
<LowPrice>6000</LowPrice>
<HighPrice>10000</HighPrice>
</PriceRange>
</Vendor>
<Vendor name=3D"Company C">
<PriceRange>
<LowPrice>500</LowPrice>
<HighPrice>2500</HighPrice>
</PriceRange>
</Vendor>
</Vendors>



_________________________________________________________________
Now you can invite friends from Facebook and other groups to join you on Wi=
ndows Live=99 Messenger. Add now.
https://www.invite2messenger.net/im/?source=3DTXT_EML_WLH_AddNow_Now=
 
S

Sharon and Dave

Here's my quick attempt

Cheers,
Dave
-----------------------------

def select_shops shops, wanted_min, wanted_max
shops.select do |shop|
(wanted_max ? wanted_max>= shop[:prices].min : true) &&
(wanted_min ? wanted_min<= shop[:prices].max : true)
end
end

shops= [{:name=> 'Company A', :prices=> 1_000.. 3_000},
{:name=> 'Company B', :prices=> 6_000..10_000},
{:name=> 'Company C', :prices=> 500.. 2_500}]

select_shops(shops, 2_500, 4_000).each do |shop|
puts shop[:name]
end
 
M

Matthew Rudy Jacobs

I assumed that input had to be taken in the way outlined in the
challenge.
So most of my code is about parsing that to create the required ranges.

=========================

class String
def better_to_f
str = match(/\D*([0-9,.]+)/)[1]
str.gsub!(',','_')
str.to_f
end
end

$vendors = <<-STRING
Company A: $1,000 - $3,000
Company B: $6,000 - $10,000
Company C: $500 - $2,500
STRING

vendor_regexp = /(\w.*\w):\s*\$([0-9,.]+) - \$([0-9,.]+)/

$shopper = <<-STRING
Low: $3,500
High: $7,000
STRING

require 'yaml'
parsed = YAML.parse($shopper)
low = parsed['Low'] && parsed['Low'].value.better_to_f
high = parsed['High'] && parsed['High'].value.better_to_f

vendors = $vendors.scan(vendor_regexp)
result = []
vendors.each do |name, min, max|
min = min.better_to_f
max = max.better_to_f

if low && low > max
next
elsif high && high < min
next
else
result << name
end
end
 

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,776
Messages
2,569,603
Members
45,190
Latest member
Martindap

Latest Threads

Top