To read on my personal blog platform, click here!
I wanted to journal about what I'd done to solve an annoying problem that I couldn't quite find a solution for online, partially to
The idea of the app is that a user can select recipes from a database, and plan to eat them later in the week. The app can then provide a master shopping list that converts 2 lbs Chicken and 8oz chicken, into a consolidated "2 1/2 lbs chicken(40oz)" so that shopping is simpler.
After setting up my database models (which I may post about at a later date) I realized that there was a major issue converting cooking measurements into code: fractions. One half was easy to represent as a float or double, its a finite number. The problem arose when we added in thirds (which you hopefully know, repeat infinitely). I didn't want to add 3 recipies each calling for a third of a cup of sugar, and then have the list say "You need to buy .9999999..... cups of sugar." Rounding could be a solution, but it seemed like an awkward way of doing things.
What would be best is if there was a library to use to convert things to and from measurements. This was what I first attempted, using The UnitsNet library. This library is excellent, and I recommend it to many people. The issue I have with it, is that it was far more in depth than what I need it to do.
The other problem was saving its measurements in my database, it was becoming painful to implement, and I knew there needed to be a better avenue.
After MUCH deliberation, I had a comment on a stackoverflow post suggest turning the measurements into an integer, which got me thinking. I eventually settled on this idea, and while I came up with the volume solution first, the solution for weight measurement is much easier to explain.
When using meat, usually you're going to measure it in pounds or ounces, with the smallest unit generally being a half ounce. So I'm translating 1 Oz to 2 "units", and a pound to 32 "units." With a simple integer, it is possible to easily store it in the database, and also add different measurements together. Once we decode the measurement "32", knowing it is measuring mass (which is done with a property on the ingredient object), we get one pound.
I've done a similar thing with volume, where the base "unit" is 1/24th of a teaspoon. therefore a teaspoon is 24 units, a tablespoon is 72 units, a cup is a lot more (24*3*2*8) units.
You can look at the methods in the service on my GitHub which as of today (7/20/21) is mostly complete, but still has some issues that I've got to figure out.
Right now, the "units" are converted to the largest possible measure. This seems like a fine solution, until you call for "1/4 Tablespoon" (18 units) and you get back "3/4 Teaspoons". This isn't wrong, in fact its the exact correct measurement, but when baking/cooking its more practical to have it in a smaller unit. Another similar case is "2 Teaspoons" (48 units), which can turn into "2/3 Tablespoons" (also 48 units). It isn't wrong, but it isn't the best response.
I'm considering fixing this a couple ways:
- Allow the user to specify the kind of measurement that should be used.
This is rather unfeasible, because if there are two recipes by different users, and one measures milk in a tablespoon, but the other measures it in a cup, the program has to decide what takes precedence.
- Hard code certain measurements
I'm considering hard coding 1/4 tbsp, 1 tsp, 1/2 tbsp, 2tsp, 3/4 tbsp, and 1 tbsp. This would ensure I always get the right kind of measurements. My concern is that it could be confusing to the user if they initially put in 3/4 Teaspoon, but it shows up as 1/4 tablespoon. They could figure out that its equivalent with some math, but it could be a confusing occurance to a first time user.
Any suggestions on which implementation should be used?
Has anyone else solved this problem a different way?