js-quantities icon indicating copy to clipboard operation
js-quantities copied to clipboard

Read available units/unit data structure

Open mikberg opened this issue 11 years ago • 10 comments

I'm looking for a way to extract (the names of) all the units available in the library, e.g. "m", "meter", "meters", "metre", "metres", "in, "inch", "inches". Is it possible to access the internal object holding these names today?

I am parsing quantities from a text input field, and want to have a typeahead feature. The way I currently do this is by a manually extracted array, which leads to errors or more labour when this library is updated.

mikberg avatar Jun 08 '14 20:06 mikberg

No, there is nothing in the current trunk to do this. But you could easily add a method to parse the UNITS variable. Maybe getPrefixes, getKinds and getUnits(kind) functions? They should be fairly easy to write.

rage-shadowman avatar Jun 09 '14 18:06 rage-shadowman

@mikberg the easy solution would be to expose the internal unit definition object for maximum usage flexibility but it would be a bad idea to let client code to mess with internal structures. So I prefer a cleaner API to retrieve these unit names. I am OK with functions proposed by @rage-shadowman. They are clear, rather simple to implement and should meet your needs as far as I understand:

getPrefixes() -> ["googol","Ki","Kibi","kibi","Mi","Mebi","mebi",...]
getKinds() -> ["resistance","inductance",...]
// optional kind parameter to filter on a specific kind, all units otherwise
getUnits("radiation") -> ["Gy","gray","grays","R","roentgen",...]

Feel free to make a PR based on this. Otherwise I will add such a feature when a little bit less busy.

gentooboontoo avatar Jun 10 '14 08:06 gentooboontoo

This looks simple and nice, perfect for my needs. I might take a swing at implementing something sometime this week.

My only concern with this API is that the different names for the same units are not grouped. Perfect for my needs, but it might not suit all.

What about something like this?

getPrefixes() -> [["googol"], ["Ki", "Kibi", "kibi"], ["Mi", "Mebi", "mebi"], ...]
getKinds() -> ["resistance", "inductance", ...]
// optional kind parameter to filter on a specific kind, all units otherwise
getUnits("radiation") -> [["Gy","gray","grays"],["R","roentgen"], ...]

mikberg avatar Jun 10 '14 08:06 mikberg

It's OK to group names since it keeps some useful information. If needed, it will be up to client code to flatten/sort or anything else with returned lists.

gentooboontoo avatar Jun 10 '14 08:06 gentooboontoo

Another alternative, if you don't want ambiguous arrays, would be to return only the unit names (ie: for "" return "liter" -- the name sans the "<>" chars) and a getAliases method to get all the aliases for a named unit (["l", "L", "liter", "liters", "litre", "litres"]) or maybe event all the alternative aliases for a given alias (such that getAlternatives("liter") returns an identical array to getAlternatives("L")).

The long names always appear to be one of the aliases, but they are not always the first alias in the list. Although getting alternatives for prefixes and for units may require separate methods (otherwise what should getAlternatives("m") return?).

rage-shadowman avatar Jun 11 '14 18:06 rage-shadowman

I went through several designs, but ended up with simply a getUnits() function returning a nested object with kinds as keys. The values are objects with unit names as keys and arrays of synonyms as values.

{
  length: {
    m: ["m", "meter", "meters", "metre", "metres",
    ...
  },
  "area": { ... },
  ...

Prefixes are also included. The return value can be restricted to only one kind by an optional "kind" argument, Qty.getUnits("prefix") or Qty.getUnits("resistance").

I'm of course open to modifying.

mikberg avatar Jun 14 '14 15:06 mikberg

@mikberg would the unit name "meter" (as opposed to "m") be more useful as the key for a unit?

rage-shadowman avatar Jun 16 '14 17:06 rage-shadowman

Yes, of course. I'm sorry, that was a typo. The real output, this time copy-pasted, is:

...,
length:
   { meter: [ 'm', 'meter', 'meters', 'metre', 'metres' ],
     inch: [ 'in', 'inch', 'inches', '"' ],
     foot: [ 'ft', 'foot', 'feet', '\'' ],
     yard: [ 'yd', 'yard', 'yards' ],
     mile: [ 'mi', 'mile', 'miles' ],
     'naut-mile': [ 'nmi' ],
     league: [ 'league', 'leagues' ],
     furlong: [ 'furlong', 'furlongs' ],
     rod: [ 'rd', 'rod', 'rods' ],
     mil: [ 'mil', 'mils' ],
     angstrom: [ 'ang', 'angstrom', 'angstroms' ],
     fathom: [ 'fathom', 'fathoms' ],
     pica: [ 'pica', 'picas' ],
     point: [ 'pt', 'point', 'points' ],
     redshift: [ 'z', 'red-shift' ],
     AU: [ 'AU', 'astronomical-unit' ],
     'light-second': [ 'ls', 'light-second' ],
     'light-minute': [ 'lmin', 'light-minute' ],
     'light-year': [ 'ly', 'light-year' ],
     parsec: [ 'pc', 'parsec', 'parsecs' ] },
  mass:
   { kilogram: [ 'kg', 'kilogram', 'kilograms' ],
     AMU: [ 'u', 'AMU', 'amu' ],
     dalton: [ 'Da', 'Dalton', 'Daltons', 'dalton', 'daltons' ]
     ...

mikberg avatar Jun 16 '14 20:06 mikberg

Thank you @mikberg for the PR. Two remarks however:

I prefer you keep your previous getPrefixes() and getKinds() methods. It would be cleaner and more logical than getUnits("prefix") (getUnits() should not reflect the internal unit definition structure that could change in the future) and getKinds could be simply implemented by returning the list of values from KINDS inner variable. Of course, getUnits("prefix") should have the same behavior than calling getUnits() with an unknown kind.

If possible (but not necessarily part of this PR), it could also be interesting to have a getAliases() / getAlternatives() method as proposed by @rage-shadowman. It would return the same array when called with any alias from a specific unit:

getAliases('m'); -> [ 'm', 'meter', 'meters', 'metre', 'metres' ]
getAliases('metres'); -> [ 'm', 'meter', 'meters', 'metre', 'metres' ]

gentooboontoo avatar Jun 17 '14 21:06 gentooboontoo

I was thinking about aliases that @gentooboontoo was discussing earlier. The main issue is there are single letter aliases that exist between many different unit types, so there is no way of knowing which unique list you would want back.

One way is to set it up to provide the alias value and the unit type. Thoughts?

vsmalladi avatar Oct 08 '15 19:10 vsmalladi