-2

I attempted to shorten my code

Code:

inv = {'arrow': 12, 'gold coin': 42, 'rope': 2, 'torch': 4, 'dagger': 1}

def show_inv():
    print('inventory:')
    item_total = 0
    for k, v in inv.items():

        print(str(v)+ ' ' + (k) )
        item_total = item_total + v

    print('total number of items: ' + str(item_total) )


show_inv()


dragon = {'gold coin': 50, 'ruby': 15}

inv.update(dragon)

print()
print('after slaying dragon:')
show_inv()

To no avail, so here i am :)

this is the

Result:

inventory:

12 arrow

42 gold coin

2 rope

4 torch

1 dagger

total number of items: 61

after slaying dragon:

inventory:

12 arrow

50 gold coin

2 rope

4 torch

1 dagger 15 ruby total number of items: 84

sean gold
  • 23
  • 2

4 Answers4

3

If you really want the shortest possible function, you could use this one-liner ;)

show_inv = lambda: print('inventory:\n%s\n%s' % ('\n'.join(['%s %s' % (k,v) for k,v in inv.items()]),'total number of items: %s' % sum(inv.values())))

(Please don't do this)

Christopher Shroba
  • 7,006
  • 8
  • 40
  • 68
3

Before you "shorten" your code make sure it's correct. Currently inv.update will just overwrite entries!

I would suggest using a Counter instead of a dict because it already implements the logic you want:

>>> from collections import Counter

>>> inv = Counter({'arrow': 12, 'gold coin': 42, 'rope': 2, 'torch': 4, 'dagger': 1})
>>> dragon = Counter({'gold coin': 50, 'ruby': 15})

>>> inv.update(dragon)
>>> inv
Counter({'arrow': 12,
         'dagger': 1,
         'gold coin': 92,    # the 42 and 50 are added!
         'rope': 2,
         'ruby': 15,
         'torch': 4})

The only function you used was show_inv. However the only purpose of this function was to print a representation of the object, there's not much you can "shorten" there. And it seems correct.

But if you have a "object" (the dict) and a function for that object, you should consider using a "class" to wrap it. There are methods that allow you to customize the "string"-representation: __str__ and __repr__ so these can be used instead of an explicit function (or method) call:

from collections import Counter

class Inventory(Counter):  # subclass Counter
    def __str__(self):     # overwrite the str-representation (this method is used by "print")
        content = ['{} {}'.format(name, cnt) for name, cnt in self.items()]
        content.insert(0, 'inventory:')
        content.append('total number of items: {}'.format(sum(self.values())))
        return '\n'.join(content)

inv = Inventory({'arrow': 12, 'gold coin': 42, 'rope': 2, 'torch': 4, 'dagger': 1})
print(inv)
# inventory:
# arrow 12
# gold coin 42
# dagger 1
# rope 2
# torch 4
# total number of items: 61

dragon = {'gold coin': 50, 'ruby': 15}
inv.update(dragon)
print(inv)
# inventory:
# ruby 15
# gold coin 92
# dagger 1
# rope 2
# torch 4
# arrow 12
# total number of items: 126
MSeifert
  • 145,886
  • 38
  • 333
  • 352
  • Thanks, programming for a while and did not now about the `Counter`, always used a dirty hacks using dicts – mucka Apr 13 '17 at 22:19
2

You can use the sum function instead of incrementally increasing the total, but besides that there aren't a whole lot of things you can do:

inv = {'arrow': 12, 'gold coin': 42, 'rope': 2, 'torch': 4, 'dagger': 1}

def show_inv():
    print('inventory:')
    for k, v in inv.items():
        print("%s %s" % (v,k))
    print('total number of items: %s' % sum(inv.values()))

show_inv()

dragon = {'gold coin': 50, 'ruby': 15}

inv.update(dragon)

print()
print('after slaying dragon:')
show_inv()
Christopher Shroba
  • 7,006
  • 8
  • 40
  • 68
  • 4
    `print("%s %s" % (v,k))` is *exactly* the same as `print(v, k)`. Similarly, `print('total number of items: %s' % sum(inv.values()))` is equivalent to `print('total number of items:', sum(inv.values()))` – vaultah Apr 13 '17 at 21:54
  • Notice, while this makes the code "shorter" it is actually taking an extra pass compared to what you are doing in the "longer" code. – juanpa.arrivillaga Apr 13 '17 at 21:56
-1

As for updating inventory you can try one liner

from functools import reduce
inv = reduce(lambda x, y: dict((k, v + y[k]) for k, v in x.items()), (inv,dragon))

Code taken from, I suggest check other answer also: How to sum dict elements

Community
  • 1
  • 1
mucka
  • 1,286
  • 3
  • 20
  • 36
  • That's not very clear. Also `iteritems` can just be `items`. – Peter Wood Apr 13 '17 at 21:57
  • What? How is this better than `inv.update(dragon)`??? I'm not even sure what this is trying to do, and it's giving me an error anyways... am I missing something? – juanpa.arrivillaga Apr 13 '17 at 21:59
  • Sure, but here clearness is traded for shortness, as for `items` you are right for Python 3.x. @juanpa.arrivillaga I am trying to sum up same items like `gold coin` here which is updated in example instead of summed up. – mucka Apr 13 '17 at 22:00
  • Shortness of *what*. As far as I can tell, this is riddled with errors. You are passing `dragon` to `reduce` which will iterate over it's *keys*, so `x` in the `lambda` will be a string, and throw an error for `x.iteritems`. Aslo, `inv` is not callable, So I'm not sure what you expect `inv((k, v + y[k]) for k, v in x.iteritems())` would do, even imagining `x.iteritems()` didn't throw an error... – juanpa.arrivillaga Apr 13 '17 at 22:01
  • The link you posted is about summing up the items in a *list of dicts* not a dictionary. This doesn't work, try it out yourself. – juanpa.arrivillaga Apr 13 '17 at 22:02
  • @mucka **`dict.items`** is also in Python 2, although maybe you're concerned about efficiency? See [this answer](http://stackoverflow.com/a/10458567/1084416) to [What is the difference between dict.items() and dict.iteritems()?](http://stackoverflow.com/questions/10458437/what-is-the-difference-between-dict-items-and-dict-iteritems) – Peter Wood Apr 13 '17 at 22:07
  • @juanpa.arrivillaga Yeah you are right, I have edited this code without running it, and it is weak because it works only if both dict have the same keys – mucka Apr 13 '17 at 22:09