0

I am still pretty new to Python and am trying to automate something I do manually. I have a sorted dictionary consisting of 6 items. The size of the dictionary will always contain 6 items, where the key is a string and value is a float.

Once I have populated my dictionary, I want to subtract the values from the dictionary in pairs i.e value from 2nd item subtracts value from first item, value from 4th item subtracts value from 3rd item and finally value from our last item in the dictionary subtracts the value from our 5th item.

When done, I print out the results.

An example of my dictionary:

my_dict = {}
my_dict = {'item1': '18.6798', 'item2': '12.638', 'item3': '20', \
     'item4': '60.00', 'item5': '65.7668', 'item6': '45.7668'}

I have been looking through dictionary comprehension in python, for loops with nested ifs (not ideal) but having trouble figuring this out. Any pointers in different ways (more efficient) that would allow me to access the index of a value within the dictionary?

    remainder = {}
        for key, value in sorted(my_dict.items()):
        ...
    print(remainder)

Once I've calculated the difference between the values, I'll store them in another dictionary which I can access by key/value.

3 Answers3

0

OK, I first divide them into pairs, and then for each pair I calculate the new value, and put in remainder:

my_dict = {'item1': 18.6798, 'item2': 12.638, 'item3': 20, \
     'item4': 60.00, 'item5': 65.7668, 'item6': 45.7668}

items = list(sorted(my_dict.keys()))
pairs = [items[i:i + 2] for i in range(0, len(items), 2)]

remainder = {}
for item1, item2 in pairs:
    remainder[item1] = my_dict[item1] - my_dict[item2]

print(remainder)


Adam.Er8
  • 12,675
  • 3
  • 26
  • 38
  • Interesting! If my_dict is always dynamic i.e the values change everytime I run the program, how would one approach this? I've been using sorted() function so far, but did some readin on OrderedDict –  Jun 23 '19 at 15:18
  • 1
    `OrderedDict` maintains the order of insertion, and `sorted` sorts by keys (or by custom func...), it's not quite the same. If for you needs what matters is the lexicographical order of the keys - then `sorted` fits better – Adam.Er8 Jun 23 '19 at 15:20
  • 1
    Ah, thanks for the explanation - now I understand better. Your solution did work and I am getting the expected data. –  Jun 23 '19 at 15:30
0

I've changed you're data so that it's a dict from str to float. This requires Python 3.7 > were dicts are ordered.

data = {
    'item1': 18.6798,
    'item2': 12.638,
    'item3': 20.0,
    'item4': 60.00,
    'item5': 65.7668,
    'item6': 45.7668,
}

Next process() is a function that takes data and (I think) does what you've asked. It works directly with iterators and doesn't require intermediate lists or dicts (but, since the data is so small, it's not really an issue)

def process(data):
    items = iter(data.items())
    result = {}
    while True:
        try:
            key_1, value_1 = next(items)
        except StopIteration:
            break
        _, value_2 = next(items)
        result[key_1] = value_1 - value_2
    return result


print(process(data))
Peter Sutton
  • 1,145
  • 7
  • 20
  • Thank you for the reply to my post Peter. I'll have a look at your solution as well and compare the two. Its interesting to see two different solutions to the problem I had at hand. One question - when does the StopIteration trigger? Is it when we trigger false in the while loop? –  Jun 23 '19 at 15:32
  • @Kanox `items` is an iterator over the items of `data`. `next()` grabs the next item from an iterator. When there are no more items a `StopIteration` exception is raised, indicating to the calling code that all items have been returned. So, I catch the `StopIteration` exception and break out of the loop. – Peter Sutton Jun 23 '19 at 15:53
0

You can zip iters made from dict.items() and then use than in a simple dictionary comprehension. If you have an odd number of keys this will ignore the last one since there's nothing to subtract:

my_dict = {'item1': '18.6798', 'item2': '12.638', 'item3': '20','item4': '60.00', 'item5': '65.7668', 'item6': '45.7668'}

f = iter(sorted(my_dict.items()))
{k1:float(v1) - float(v2) for ((k1, v1), (k2, v2)) in zip(f,f)}

Result:

{'item1': 6.0418, 'item3': -40.0, 'item5': 20.0}
Mark
  • 90,562
  • 7
  • 108
  • 148
  • Is the dictionary comprehension a simpler version of a for loop? –  Jun 23 '19 at 15:33
  • @Kanox -- sort of, it builds the dictionary in place the same way a list comprehension does. Comprehensions very *pythonic* ways of building things like lists and dicts. There's a [good thread here](https://stackoverflow.com/questions/14507591/python-dictionary-comprehension) – Mark Jun 23 '19 at 15:34
  • Gotcha - thank you. I've given you a upvote as your solution also works and its something that I was so very close to getting! –  Jun 23 '19 at 15:38