Use a generator expression:
sum(c.a for c in c_list)
Answer from phihag on Stack OverflowYou can do this using a defaultdict:
from collections import defaultdict
indexed_sums = defaultdict(int)
for o in xbs:
indexed_sums[(o.W, o.X, o.Y)] += o.Z
For instance, if you start with (using your class definition of xb):
xbs = [xb(1, 2, 3, 4, 5),
xb(1, 2, 3, 4, 5),
xb(1, 2, 3, 4, 5),
xb(1, 4, 3, 4, 5),
xb(1, 4, 3, 4, 3),
xb(1, 2, 3, 9, 3)]
You end up with:
print dict(indexed_sums)
# {(4, 3, 4): 8, (2, 3, 4): 15, (2, 3, 9): 3}
Thus, you could get the sum for W, X, Y being 2, 3, 4 as:
indexed_sums[(2, 3, 4)]
# 15
Note that the defaultdict is doing very little work here (it's just a dictionary of counts that starts at 0 by default): the main thing is that you are indexing the (o.W, o.X, o.Y) tuples in a dictionary. You could have done the same thing without defaultdict as:
indexed_sums = {}
for o in xbs:
if (o.W, o.X, o.Y) not in indexed_sums:
indexed_sums[(o.W, o.X, o.Y)] = 0
indexed_sums[(o.W, o.X, o.Y)] += o.Z
The defaultdict is just saving you two lines.
Here's a very dirty hack of a one-liner:
{key:sum(g.Z for g in group)
for key, group in
itertools.groupby(
sorted(L, key=lambda p:tuple((operator.attrgetter(a)(p) for a in 'VWXYZ'))),
key=lambda p:tuple(
(operator.attrgetter(a)(p) for a in 'VWXYZ')
)
)
}
I don't recommend doing this at all (it's a pain to debug), but I think it's an interesting solution nonetheless
python - Sum a list of object attributes - Stack Overflow
Python - Sum by Unique Attributes in a List of Attributes - Stack Overflow
python - List of Objects: Efficiently getting a list of sum of ith attribute - Stack Overflow
What's the most concise way in Python to group and sum a list of objects by the same property - Stack Overflow
sum needs somewhere to start; by default, it starts at 0. So the first operation it attempts is 0 + MyClass(value=1), which you haven't told it how to do!
You therefore have two choices, either:
- Specify the
start(e.g.sum(c, MyClass())); or - Tell
MyClasshow to deal with adding integers to instances.
The latter could look like:
class MyClass(object):
...
def __add__(self, other):
try:
return MyClass(self.value + other.value) # handle things with value attributes
except AttributeError:
return MyClass(self.value + other) # but also things without
...
which lets you skip the explicit start:
>>> sum([MyClass(1), MyClass(2)]).value
3
Because sum(iterable[, start]) sums start and the items of an iterable from left to right and returns the total. start defaults to 0.
You can modify the class by
class MyClass(object):
def __init__(self, value=0):
self.value = value
def __add__(self, other):
if (isinstance(other, MyClass)):
return MyClass(other.value + self.value)
else:
return MyClass(other + self.value)
__radd__ = __add__
Use itertools.groupby after sorting it with operator.attrgetter('name') as key.
from itertools import groupby
from operator import attrgetter
print({k: sum(o.value for o in g) for k, g in groupby(sorted(listOfObj, key=attrgetter('name')), attrgetter('name'))})
Try using itertools.groupby to group the objects by name and then get the sum of grouped objects
from itertools import groupby
f = lambda x: x.name
d = {name:sum(obj.value for obj in grouped_objs) for name,grouped_objs in groupby(sorted(listOfObj, key=f), f)}
You can use the inspect module to extract a list of all arguments required to initialise a class instance.
Then iterate those arguments with a list comprehension:
import inspect
class Foo():
def __init__(self, a1, a2, a3):
self.a1 = a1
self.a2 = a2
self.a3 = a3
pass
# get list of arguments, ignore the first which is self
args = inspect.getfullargspec(Foo.__init__).args[1:]
l = [Foo(a1=1, a2=2, a3=3), Foo(a1=1, a2=2, a3=3), Foo(a1=1, a2=2, a3=3)]
# use list comprehension to sum by attribute
sums = [sum([getattr(x, i) for x in l]) for i in args]
# [3, 6, 9]
The main idea is to use the getattr built-in function that returns the value of an attribute, using its name:
class Foo:
def __init__(self,a1,a2,a3):
self.a1 = a1
self.a2 = a2
self.a3 = a3
l = [Foo(a1 = 1, a2 = 2, a3 = 3), Foo(a1 = 1, a2 = 2, a3 = 3), Foo(a1 = 1, a2 = 2, a3 = 3)]
sums = [sum([getattr(x,'a{}'.format(i)) for x in l]) for i in range(1,4)]
The defaultdict approach is probably better, assuming c.Y is hashable, but here's another way:
from itertools import groupby
from operator import attrgetter
get_y = attrgetter('Y')
tuples = [(y, sum(c.Z for c in cs_with_y) for y, cs_with_y in
groupby(sorted(cs, key=get_y), get_y)]
To be a little more concrete about the differences:
This approach requires making a sorted copy of
cs, which takes O(n log n) time and O(n) extra space. Alternatively, you can docs.sort(key=get_y)to sortcsin-place, which doesn't need extra space but does modify the listcs. Note thatgroupbyreturns an iterator so there's not any extra overhead there. If thec.Yvalues aren't hashable, though, this does work, whereas thedefaultdictapproach will throw aTypeError.But watch out -- in recent Pythons it'll raise
TypeErrorif there are any complex numbers in there, and maybe in other cases. It might be possible to make this work with an appropriatekeyfunction --key=lambda e: (e.real, e.imag) if isinstance(e, complex) else eseems to be working for anything I've tried against it right now, though of course custom classes that override the__lt__operator to raise an exception are still no go. Maybe you could define a more complicated key function that tests for this, and so on.Of course, all we care about here is that equal things are next to each other, not so much that it's actually sorted, and you could write an O(n^2) function to do that rather than sort if you so desired. Or a function that's O(num_hashable + num_nonhashable^2). Or you could write an O(n^2) / O(num_hashable + num_nonhashable^2) version of
groupbythat does the two together.sblom's answer works for hashable
c.Yattributes, with minimal extra space (because it computes the sums directly).philhag's answer is basically the same as sblom's, but uses more auxiliary memory by making a list of each of the
cs -- effectively doing whatgroupbydoes, but with hashing instead of assuming it's sorted and with actual lists instead of iterators.
So, if you know your c.Y attribute is hashable and only need the sums, use sblom's; if you know it's hashable but want them grouped for something else as well, use philhag's; if they might not be hashable, use this one (with extra worrying as noted if they might be complex or a custom type that overrides __lt__).
from collections import defaultdict
totals = defaultdict(int)
for c in cs:
totals[c.Y] += c.Z
tuples = totals.items()
Hey guys, I'm learning Python on code academy and I'm stuck on this question. What am I doing wrong?
-
Write a function average that takes a list of numbers and returns the average.
-
Define a function called average that has one argument, numbers.
-
Inside that function, call the built-in sum() function with the numbers list as a parameter. Store the result in a variable called total.
-
Like the example above, use float() to convert total and store the result in total.
-
Divide total by the length of the numbers list. Use the built-in len() function to calculate that.
-
Return that result.
Is this right?
def average(numbers): total = numbers.sum() total = float(total) return len(total)
I don't know how to add indentation on this thing but assume there is one.
as the input is:
my_list = [
{
'brand': 'Totoya',
'quantity': 10
},
{
'brand': 'Honda',
'quantity': 20
},
{
'brand': 'Hyundai',
'quantity': 30
}
]
You can loop over it as this:
counter = 0
for i in my_list:
counter += i['quantity']
print(counter)
or in oneliner:
print(sum(i['quantity'] for i in my_list))
Python contains good functions for functional programming.
my_list = ...
# Select the quantities from my_list
quantities = map(lambda x: x['quantity'], my_list)
# Computes the sum of quantities
total = sum(quantities)
I'm going to assume that your CSV file is in fact a CSV file. Comma is the delimiter and the quotechar is the single quote char '.
Counting the number of times that (zero-based) column 3 occurs for each store in column 0 requires grouping the data by column 0. One way to do that is with a dictionary. A collections.defaultdict is a type of dictionary that makes it easy to collect lists of values with a common key. Once you have that you can produce counts of the "Blue" items, or "Red", or whatever else you might have.
import csv
from collections import defaultdict
d = defaultdict(list)
with open('count.csv') as f:
for row in csv.reader(f, quotechar="'"):
d[row[0]].append(row[3])
for k in sorted(d):
print('{},{}'.format(k, d[k].count('Blue')))
Output
Store A,2 Store B,2 Store C,3
That doesn't look like a CSV file, it looks like one Python list per line. Read it with literal_eval and feed it to a Counter:
from ast import literal_eval
from collections import Counter
blues = Counter()
with open("count.csv") as f:
for line in f:
ls = literal_eval(line)
if ls[3] == 'Blue':
blues[ls[0]] += 1
If you want to print it in your desired output format:
for key in blues:
print("['{}', 'Blue', {}]".format(key, blues[key]))
In Python, it's generally better to loop directly over the items in a list, rather than looping indirectly using indices. It's easier to read, and more efficient not to muck around with indices that you don't really need.
To get a total for each mini_carpet you can do this:
for mini in carpet:
nr_total = sum(package.nr_buys for package in mini)
# Do something with nr_total
To get a single grand total, do a double for loop in the generator expression:
nr_total = sum(package.nr_buys for mini in carpet for package in mini)
for d in range(0, len(carpet) - 1, +1):
nr_total = sum(carpet[d].packages[i].nr_buys for i, _ in enumerate(carpet[d].packages))
You want to get the indexes of a dict, so use enumerate, which returns a tuple: (index, item).
Also, why are you using dict.__len__?
First off - sum doesn't need a list - you can use a generator expression instead:
atotal = sum(x.acounter for x in someList)
You could write a helper function to do the search of the list once but look up each attribute in turn per item, eg:
def multisum(iterable, *attributes, **kwargs):
sums = dict.fromkeys(attributes, kwargs.get('start', 0))
for it in iterable:
for attr in attributes:
sums[attr] += getattr(it, attr)
return sums
counts = multisum(someList, 'acounter', 'bcounter')
# {'bcounter': 45, 'acounter': 45}
Another alternative (which may not be faster) is to overload the addition operator for your class:
class Some(object):
def __init__(self, acounter, bcounter):
self.acounter = acounter
self.bcounter = bcounter
def __add__(self, other):
if isinstance(other, self.__class__):
return Some(self.acounter+other.acounter, self.bcounter+other.bcounter)
elif isinstance(other, int):
return self
else:
raise TypeError("useful message")
__radd__ = __add__
somelist = [Some(x, x) for x in range(10)]
combined = sum(somelist)
print combined.acounter
print combined.bcounter
This way sum returns a Some object.