Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently sum items by type

I have a list of items with properties "Type" and "Time" that I want to quickly sum the time for each "Type" and append to another list. The list looks like this:

Items = [{'Name': A, 'Type': 'Run', 'Time': 5},  
          {'Name': B, 'Type': 'Walk', 'Time': 15},  
          {'Name': C, 'Type': 'Drive', 'Time': 2},
          {'Name': D, 'Type': 'Walk', 'Time': 17},  
          {'Name': E, 'Type': 'Run', 'Time': 5}]

I want to do something that works like this:

Travel_Times=[("Time_Running","Time_Walking","Time_Driving")]
Run=0
Walk=0
Drive=0    

for I in Items:
    if I['Type'] == 'Run':
       Run=Run+I['Time']
    elif I['Type'] == 'Walk': 
       Walk=Walk+I['Time']           
    elif I['Type'] == 'Drive': 
       Drive=Drive+I['Time']           

Travel_Times.append((Run,Walk,Drive))    

With Travel_Times finally looking like this:

print(Travel_Times)
[("Time_Running","Time_Walking","Time_Driving")
 (10,32,2)]

This seems like something that should be easy to do efficiently with either a list comprehension or something similar to collections.Counter, but I can't figure it out. The best way I have figured is to use a separate list comprehension for each "Type" but that requires iterating through the list repeatedly. I would appreciate any ideas on how to speed it up.

Thanks

like image 293
Notabrick Avatar asked Apr 12 '17 18:04

Notabrick


People also ask

Which is a quick way to sum up a set of numbers?

Using the Formula We can put what Gauss discovered into an easy-to-use formula, which is: (n / 2)(first number + last number) = sum, where n is the number of integers. Let's use the example of adding the numbers 1-100 to see how the formula works.

How do you sum a range of cells in Excel?

If you need to sum a column or row of numbers, let Excel do the math for you. Select a cell next to the numbers you want to sum, click AutoSum on the Home tab, press Enter, and you're done. When you click AutoSum, Excel automatically enters a formula (that uses the SUM function) to sum the numbers.

Is sum faster than for loop?

A key difference between R and many other languages is a topic known as vectorization. When you wrote the total function, we mentioned that R already has sum to do this; sum is much faster than the interpreted for loop because sum is coded in C to work with a vector of numbers.

Are Python Builtins faster?

Use the Built-In FunctionsMany of Python's built-in functions are written in C, which makes them much faster than a pure python solution. Take a very simple task of summing a lot of numbers. We could loop through each number, summing as we go.


2 Answers

Note that case is very important in Python :

  • For isn't a valid statement
  • Travel_times isn't the same as Travel_Times
  • there's no : after elif
  • Travel_Times.append(... has a leading space, which confuses Python
  • items has one [ too many
  • A isn't defined

Having said that, a Counter works just fine for your example :

from collections import Counter

time_counter = Counter()

items = [{'Name': 'A', 'Type': 'Run', 'Time': 5},  
          {'Name': 'B', 'Type': 'Walk', 'Time': 15},  
          {'Name': 'C', 'Type': 'Drive', 'Time': 2},
          {'Name': 'D', 'Type': 'Walk', 'Time': 17},  
          {'Name': 'E', 'Type': 'Run', 'Time': 5}]

for item in items:
    time_counter[item['Type']] += item['Time']

print(time_counter)
# Counter({'Walk': 32, 'Run': 10, 'Drive': 2})

To get a list of tuples :

[tuple(time_counter.keys()), tuple(time_counter.values())]
# [('Run', 'Drive', 'Walk'), (10, 2, 32)]
like image 90
Eric Duminil Avatar answered Oct 20 '22 01:10

Eric Duminil


You can use a dict to keep track of the total times. Using the .get() method, you can tally up the total times. If the key for the activity doesn't already exist, set its tally to zero and count up from there.

items = [{'Name': 'A', 'Type': 'Run', 'Time': 5},  
          {'Name': 'B', 'Type': 'Walk', 'Time': 15},  
          {'Name': 'C', 'Type': 'Drive', 'Time': 2},
          {'Name': 'D', 'Type': 'Walk', 'Time': 17},  
          {'Name': 'E', 'Type': 'Run', 'Time': 5}]

totals = {}

for item in items:
    totals[item['Type']] = totals.get(item['Type'], 0) + item['Time']

for k, v in totals.items():
    print("Time {}ing:\t {} mins".format(k, v))
like image 24
roganjosh Avatar answered Oct 20 '22 00:10

roganjosh