1

I'm having an hard time figuring an efficient way to converts differents types of unit to various other types.

Switch cases would work, but IMO that's not an efficient way has I will have 3 different Systems (SI, Imperial and US).

My converter (inside my app) will always convert from SI to something or from something to SI. It kinds of lower the complexity, but yet I still need advice on how to make clean code.

I had defined that my input parameters for conversion would be Value(number) and Unit(string).
I would have 2 functions. SIToSomething(value, unit) and SOmethingToSi(value, unit).

Unit is defined because I would be converting length, weight, qty etc..

What would you suggest ?

Fawar
  • 735
  • 2
  • 11
  • 32
  • see [Alternative to a million IF statements](http://stackoverflow.com/questions/10029089/alternative-to-a-million-if-statements) – Bergi Jun 20 '13 at 17:31

3 Answers3

3

How about this:

var converters = {
    'SIToImperial' : {
        'cm' : function(val) {
            // implementation, return something
        },
        'kg' : function(val) {
            // implementation, return something
        } //, etc.
    },
    'SIToUS' : {
        'cm' : function(val) {
            // implementation, return something
        },
        'kg' : function(val) {
            // implementation, return something
        } //, etc.
    },
    'USToSI' : {
        'cm' : function(val) { /* ... */ } // etc
    } // , etc
}

SIToSomething(value, unit, system) {
    return converters["SITo" + system][unit](value);
}

var meterInImperial = SIToSomething(100, 'cm', 'Imperial');
var fiftyKilosInUS = SIToSomething(50, 'kg', 'US');
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • Well I would still be stuck with 4 big switch case, One for SiToIMp, SIToUS, USToSI,IMPToSi... That's what I'm trying not to do :P – Fawar Jun 20 '13 at 16:53
  • That would not be a switch case. It would be a table of functions. You can even define each function at a different place. – John Dvorak Jun 20 '13 at 16:55
  • I'm not sure I understand, but edited to take care of both unit and system. I don't see why it would require any switches. @Fawar – bfavaretto Jun 20 '13 at 16:56
  • Looks perfectly sensible to me +1 – Xotic750 Jun 20 '13 at 17:03
  • I'm not familiar with array of functions or OOP in JS. I missed the part that these were functions in an array :S. Following what I now understand( I think) you would have SIToImperial with every unit, SIToUS with every unit again but with different functions and the reverse-alternative IMPToSi and USToSI. So somehow I would have 4 identical tables with different functions to call. Would there be anyway to have one table that call the right function (lowering memory usage). – Fawar Jun 20 '13 at 17:06
  • @Fawar It's actually an object, not an array. The converter functions are properties of that object, and can be accessed by name via bracket notation. I believe you only need one object/table to hold all your functions, I'll add more examples. – bfavaretto Jun 20 '13 at 17:33
  • Also, I organized the object by system, then unit, but it could also be unit, then system. Your call. – bfavaretto Jun 20 '13 at 17:36
  • Thank you, I'll be using your idea, might modify it a bit but that's seem way better than what I was building XD – Fawar Jun 20 '13 at 19:52
  • it would have been nice to be able not to repeat *System* in every *Particular Unit* property or in the alternative *Particular Unit* in every *System*. I guess it's kind of nearly impossible to keep simple if we were to achieve such a thing since it would need somekind of way to determine which function to compute. – Fawar Jun 20 '13 at 19:56
  • @Fawar I guess some level of repetition is unavoidable. And I'm glad I helped! – bfavaretto Jun 20 '13 at 19:59
2

What you can do is have a base unit, and for each target unit, define conversion functions to/from this base unit. Then, to convert from A to B, for example, you'd have this:

A -> base -> B

This way, you only need two conversion functions per unit (not counting the base unit):

var units = {
    a: {
        toBase: function(value) { return value * 2; },
        fromBase: function(value) { return value / 2; }
    },
    b: {
        toBase: function(value) { return 1.734 * value + 48; },
        fromBase: function(value) { return (value / 1.734) - 48; }
    }
}

function convertFromTo(unitA, unitB, value) {
    return unitB.fromBase(unitA.toBase(value));
}

convertFromTo(units.a, units.b, 36489);
Jacob
  • 77,566
  • 24
  • 149
  • 228
  • I defined that SI would be that base unit :P That why I only Have from SI and To Si – Fawar Jun 20 '13 at 17:06
  • OK, missed that you were already going to convert to a base unit, but my table of unit conversions is still good. – Jacob Jun 20 '13 at 17:11
  • What are the type of unitA and unitB in the convertFromTo function? a and b are different measure unit ( IE Grams and liters?) – Fawar Jun 20 '13 at 17:24
  • I'd assume you'd have a different set of units for each category, like `lengthUnits`, `weightUnits`, etc. – Jacob Jun 20 '13 at 17:31
  • I don't know the specific Imperial and US units in question, so I stuck with "a" and "b". Could have been "Fahrenheit" and "Celsius" both converting to "Kelvin" as the base, for example. – Jacob Jun 20 '13 at 17:32
  • Okay i got that part :P but what are unitA and unitB are they strings or int or object? Not quite sure to get that part. – Fawar Jun 20 '13 at 19:51
0

Do all conversions to/from SI. For example if converting Imperial->US, you'd go Imperial->SI->US.

This is minimal effort you can put in. It also gets you SI "for free".

ninjagecko
  • 88,546
  • 24
  • 137
  • 145
  • That is what I want to do. What I need is better way than switch case to convert grams or liters or whatever. Array of Function seems a good way to go. – Fawar Jun 20 '13 at 17:25