0

I'm making a unit converting function for Python for fun.

This is my code, so far:

def UnitConverter(number,*units):
 if units == ("feet","inches"):
 return number*12
 elif units == ("ft","yd"):
 return number/3

You probably get the idea of how I'm having this work.

Because I'm obsessive about elegance, good code practice, and overall flow, I want to know what you coders think about this in general, in addition to my main question: How can I efficiently check for a list of permutations in an if statement?

Example: Is there an efficient way to make this work?

def UnitConverter(number,*units):
 if units == (("feet" or "foot" or "ft."),("inches" or "in" or "in.")):
 return number*12
 elif units == ("ft","yd"):
 return number/3

If not, is there a way to restructure my program such that someone can enter the three arguments number, unit1, unit2 in a way that on the coding end, I can effectively include all alternate spellings of each unit (feet,foot,ft,etc)?

I really value everyone's opinion.

Thanks!

asked Oct 25, 2013 at 19:53
7
  • 1
    Why are you accepting *units and then repeatedly implicitly forcing it to be two values, instead of just accepting, say, fromunit, tounit as two separate parameters? Commented Oct 25, 2013 at 20:01
  • 1
    Also, trying to handle the cartesian product of N units with N-1 other units is going to mean a whole lot of code if N is much better than 3. Why not do this in two steps: convert from the fromunit to some canonical unit, then convert from the canonical unit to the tounit. Then you only need N*2 if conditions instead of N**2. Commented Oct 25, 2013 at 20:02
  • 1
    +1 to abarnert, except make it from_unit and to_unit Commented Oct 25, 2013 at 20:10
  • @abarnert I'm using *units because I originally planned to return as many conversions as the user wanted, a one-to-many conversion. Commented Oct 26, 2013 at 21:18
  • 1
    One more suggestion here: The (BSD or GNU) units tool does almost exactly what you want, and it comes with a nifty, relatively easy-to-parse data file units.lib that can be used to build, e.g., the dictionary used in RemcoGerlich's answer. Commented Oct 30, 2013 at 18:13

3 Answers 3

4

I would pick a standard unit of length, let's say m. Then I would have a single dictionary that gives a factor for each other unit, and convert:

conversion_factors = {
 'foot': 0.3048, # Google search '1 foot in m'
 'yard': 0.9144,
 # etc
}
def unit_convert(number, from_unit='m', to_unit='m'):
 m = number * conversion_factor[from_unit]
 return m / conversion_factor[to_unit]

For the synonyms (feet, ft, etc) you could make a second dictionary and lookup the canonical name in that first:

conversion_factors = { ... } # as above
synonyms = {
 'feet': 'foot',
 'ft': 'foot',
 ...
}
def unit_convert(number, from_unit='m', to_unit='m'):
 from_unit = synonyms.get(from_unit, from_unit)
 to_unit = synonyms.get(to_unit, to_unit)
 # etc

...or just put them in the conversion_factors dictionary multiple times:

conversion_factors = {
 'foot': 0.3048, # Google search '1 foot in m'
 'feet': 0.3048,
 'ft': 0.3048,
 'yard': 0.9144,
 # etc
}
answered Oct 25, 2013 at 20:03
Sign up to request clarification or add additional context in comments.

1 Comment

This is exactly how I'd write it... but you should add one example of how it solves the problem the OP had in the first place: multiple names for the same unit. Just add 'feet': 0.3048,.
4

Use sets.

foot_units = {"ft.", "feet", "foot"}

Then you can check ownership in the sets.

if(units[0] in foot_units):
 ...

Beyond this, make a conversion_factor dictionary that goes to a common conversion element. You can then coerce to your final after.

inches -> feet -> yards
inches -> feet -> feet

RemcoGerlich has a good solution for that step.

answered Oct 25, 2013 at 19:57

1 Comment

If you want to simplify this, I'd use a single 1D table to convert each unit to/from a single canonical unit, instead of a 2D table, which is going to explode combinatorially (and we all know how messy that can be) just like the OP's code.
2

Perhaps something like the following, using the in operator which checks for containment:

def UnitConverter(number,*units):
 feet = {'feet', 'foot', 'ft.'}
 inches = {'inches', 'in', 'in.'}
 yards = {'yard', 'yd', 'yd.'}
 if units[0] in feet and units[1] in inches:
 return number*12
 elif units[0] in feet and units[1] in yards:
 return number/3
answered Oct 25, 2013 at 19:56

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.