0

I am using Python 3.3.3. I am trying to write my second Python program (my first somewhat difficult project (for a novice)), it's a weight loss tracker that includes a pictograph for visual reference. I have made everything work until now. The problem I am having is in writing a function that will take the input int or float and then break it down in to its parts (10s, 5s, 1s, and tenths) ready to be used in unison with the pictograph function I will be writing.

I have considered using a dictionary to store those values just to get some practice with using them. I don't know how to approach the problem. If there is an easier solution besides using a dictionary, by all means, please share your thoughts.

def get_digits(weight_entry):
"""(int or float) -> (dict)

Takes user input int or float weight_entry, and returns a populated dict
separated in to tens, fives, ones, and tenths.

>>>get_digits(279.6)
{'tens': 27, 'fives': 1, 'ones': 4, 'tenths': 6}
>>>get_digits(236.5)
{'tens': 23, 'fives': 1, 'ones': 1, 'tenths': 5}
>>>get_digits(224.2)
{'tens': 22, 'fives': 0, 'ones': 4, 'tenths': 2}
"""
get_digits_dict = {'tens': 0, 'fives': 0, 'ones': 0, 'tenths': 0}
digits_string = str(weight_entry)
populate_tens = get_digits_dict['tens'] = int(digits_string[:2])

The reason it's broken up in to tens that way is because each 10 corresponds to 1, 10 valued shape.

You can see I've tried converting the number in to a string, and then just use slicing to get the portion I want, and then return it to an int. I've also tried taking the bulk of it all out by taking the tens completely out, leaving me with, instead of 277.6, 7.6, from which I can try to do some simple math to get what I need. From 7.6 what I would need to get is one five, two ones, and six tenths.

my output, besides the time stamp I intend to add, is supposed to come out as such:

265.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ □ ▪

263.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ □ ▫▫▫

260.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ □

259.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ ▪▫▫▫▫

256.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ ▪▫

257.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ ▪▫▫

254.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ ▫▫▫▫

251.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□□ ▫

249.0 □□□□□ □□□□□ □□□□□ □□□□□ □□□□ ▪▫▫▫▫

245.6 □□□□□ □□□□□ □□□□□ □□□□□ □□□□ ▪ ∙∙∙∙∙∙

244.3 □□□□□ □□□□□ □□□□□ □□□□□ □□□□ ▫▫▫▫ ∙∙∙

244.1 □□□□□ □□□□□ □□□□□ □□□□□ □□□□ ▫▫▫▫ ∙

239.7 □□□□□ □□□□□ □□□□□ □□□□□ □□□ ▪▫▫▫▫ ∙∙∙∙∙∙∙

I am a systematic creature, so naturally I want to do the 5s next. Well, I can assume there will only be one five if there is ever a five, and that five will be present only if the number in the literal ones place, is between 5 and 9. After the 5s, any excess from the ones place would be used to capture the ones, and the excess after the decimal is the tenths, of course. My main problem is finding the five, and then the excess for the ones.

I guess I am just a bit overwhelmed and frustrated because this is kind of out of my league, but that is just me, I am trying to step up by learning from things just outside my reach. I would spend more hours trying to write this function, but I feel I would learn more from not figuring it out, someone showing me, and then just analyzing all the places I went wrong.

Any help at all would be greatly appreciated. If you read this far, I appreciate that too.


WOW So informative, all of you. I had thought to use floor division and/or modulo but I couldn't figure out how to yield the exact result. If I had the rep to +1 you all, I would. I will choose the answer that comes closest to what I intended to accomplish, after I complete my program, although I may use a combination of everyone's responses to yield the final result. Thanks for helping me learn.

Getting the five, and the excess ones were proving troublesome to isolate. As well as the precision of the decimal was making it hard to figure out as a whole. Thanks to all who contributed.

Ryan Prince
  • 27
  • 2
  • 7
  • 1
    I think you can just: divide by 10 take the integer part, divide remainder by 5, take the integer part, divide remainder by 1 (hah) take the integer part, divide remainder by 0.1, take the integer part. – towr Jan 17 '14 at 20:40
  • Okay, I think I was just over thinking. Thank you. – Ryan Prince Jan 17 '14 at 20:41

4 Answers4

2

You can use the Python // operator for this task.

You can read about the operator in this answer:
Python 3 integer division. How to make math operators consistant with C).

n = 749.65

tens = n // 10
n = n - 10 * tens

fives = n // 5
n = n - 5 * fives

ones = n // 1
n = n - 1 * ones

tenths = n // .1
n = n - .1 * tenths

remainder = n

This should give you the following.

tens = 74
fives = 1
ones = 4
tenths = 6
remainder = .05

Due to inexact computation the result may be off slightly. If that's a problem you could use base 10 instead of base 2; i.e., use n = Decimal("749.65") instead. Read more about Decimal here: http://www.python.org/dev/peps/pep-0327/#abstract

Community
  • 1
  • 1
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • Wouldn't using `n = n % 10` be more efficient than `n = n - 10 * tens` ? (Unless `%` is harder than `*` ?) – towr Jan 17 '14 at 20:45
  • @towr You could absolutely do it the way you're suggesting. (I don't know whether it's more efficient or not.) I just went this route because I thought it was a little easier to understand. – Timothy Shields Jan 17 '14 at 20:47
1

You can use a greedy algorithm to make change. Here is how I would encapsulate it into a basic function:

def get_digits(weight_entry):
    out = {}
    entries = ('tens',10),('fives',5),('ones',1),('tenths',.1)
    for word,num in entries:
        out[word] = weight_entry // num
        weight_entry %= num
    return out

demo

get_digits(116.4)
Out[53]: {'fives': 1.0, 'ones': 1.0, 'tens': 11.0, 'tenths': 4.0}

Note that floating-point arithmetic can be surprising:

get_digits(114.3)
Out[54]: {'fives': 0.0, 'ones': 4.0, 'tens': 11.0, 'tenths': 2.0}

It's possible to lose a tenth due to rounding errors. You can correct for this in a number of ways, i.e:

def get_digits(weight_entry):
    out = {}
    entries = ('tens',10),('fives',5),('ones',1),('tenths',.1)
    for word,num in entries:
        out[word] = weight_entry // num
        weight_entry %= num
    if round(weight_entry,1): #correction for floating-point error
        out['tenths'] += 1
    return out
roippi
  • 25,533
  • 4
  • 48
  • 73
  • That's funny, basically the same thing. =/ I correct by multiplying then dividing by 10, but your way might be more clear. – Chris Arena Jan 17 '14 at 21:17
0

https://en.wikipedia.org/wiki/Change-making_problem - Try this, there are at least two solutions decribed.

Filip Malczak
  • 3,124
  • 24
  • 44
0

Here's a solution that uses the modulus operator and integer division. I multiply then divide the number by 10 initially so that I can get the tenths accurately (and get rid of any extra precision if given by making it an integer when it's 10 times).

At the start I set up a list of tuples so that I know what each of those strings mean, and then I can just iterate through all of the tuples in the list.

values = [('tens', 10), ('fives', 5), ('ones', 1), ('tenths', 0.1)]


def get_digits(num):
    num = int(num * 10)
    num = float(num) / 10

    output_dict = {}
    for place, value in values:
        output_dict[place] = num // value
        num = num % value
    return(output_dict)

get_digits(123.456)

Output:

{'fives': 0.0, 'tens': 12.0, 'tenths': 4.0, 'ones': 3.0}

Here's a cool visualizer that might help you understand how the dict here is being generated if you paste in the above code: http://pythontutor.com/visualize.html

Chris Arena
  • 1,602
  • 15
  • 17