开发者

Python: Summing class instances inside a list

开发者 https://www.devze.com 2023-03-25 22:52 出处:网络
I am familiar with the built-in sum() function for lists and have used it before, eg: sum(list1[0:41])

I am familiar with the built-in sum() function for lists and have used it before, eg:

sum(list1[0:41])

when the list contains integers, but I'm in a situation where I have instances from a Class and I need them summed.

I have this Class:

class DataPoint:
    def __init__(self, low, high, freq):
        self.low = low
        self.high = high
        self.freq = freq

They all refer to floats from an XML file and these instances later go into a list in my code.

So for instance, I want to be able to do something like:

sum(list[0:41].freq)

where the list contains the Class instances.

I'm also trying to get it in a loop so that the second number in the range of the sum() goes up each time, eg:

for i in range(len(list)):
    sum(list[0:i+1].freq)

Anyone know how I can get around this or if there is another way to do it?

Thanks!

UPDATE:

Thanks for all the responses, I'll try to provide something more concrete than the conceptual stuff I put up there first:

# Import XML Parser
import xml.etree.ElementTree as ET

# Parse XML directly from the file path
tree = ET.parse('xml file')

# Create iterable item list
items = tree.findall('item')

# Create class for historic variables
class DataPoint:
    def __init__(self, low, high, freq):
        self.low = low
        self.high = high
        self.freq = freq

# Create Master Dictionary and variable list for historic variables
masterDictionary = {}

# Loop to assign variables as dictionary keys and associate their values with them
for item in items:
    thisKey = item.find('variable').text
    thisList = []
    masterDictionary[thisKey] = thisList

for item in items:
    thisKey = item.find('variable').text
    newDataPoint = DataPoint(float(item.find('low').text), float(item.find('high').text), float(item.find('freq').text))
    masterDictionary[thisKey].append(newDataPoint)

# Import random module for pseudo-random number generation
import random

diceDi开发者_如何学运维ctionary = {}

# Dice roll for historic variables
for thisKey in masterDictionary.keys():
    randomValue = random.random()
    diceList = []
    diceList = masterDictionary[thisKey]
    for i in range(len(diceList)):
        if randomValue <= sum(l.freq for l in diceList[0:i+1]):
            diceRoll = random.uniform(diceList[i].low, diceList[i].high)
            diceDictionary[thisKey].append(diceRoll)

I am basically trying to create a dictionary of dice rolls to match the keys of my master dictionary with the data. The freq instance of my Class refers to probabilities of certain bins being applied and are determined by a dice roll (random number). This is what the summing is for.

Maybe this helps clear up my intention? The "i" in the summing example will be whatever the number of data points for a certain variable.

Once I have the dictionaries of which rolls were selected in my out loop (not shown here), I'll apply it to code below to make something meaningful.

Let me know if there is still any confusion about my intention. I will try a few of these suggestions out, but maybe someone can break it down to the simplest form considering what I've provided.

Thanks!


Have you tried:

sum(i.freq for i in items[0:41])

If you need the cumulative sum of the last "i" elements, the following is the most efficient approach:

sums = [items[0].freq]
for i in items[1:]:
    sums.append(sums[-1] + i.freq)

As other posters already have anticipated, it is a bad programming style to use name of builtins for your variables; I have replace list with items in the code above.


Your last example would have quadratic complexity. A much simpler way would be to just keep a running total:

total = 0
for x in list:
    total += x.freq  # total at this point is equal to the sum in your example
# and total at this point is the grand total

If you don't need the running-sum for each item in the list, but just the grand total, then refer to GaretJax's answer, which uses sum.

Also, list is a built-in type, so you probably don't want to use it as a variable name (which would overwrite the built-in).


For the first use case, something like

sum(dp.freq for dp in dp_list[:41])

would most likely be suitable.

But if you want to do cumulative sums anyways, you could technically just combine them, as the total sum will be the last total sum. For example,

cumsums = []
for i, dp in enumerate(dp_list):
    if cumsums:
        cumsums.append(dp.freq + cumsums[-1])
    else:
        cumsums.append(dp.freq)

and then cumsums[40] would be the sum of the freqs of the first 41 DataPoints. You could probably even optimize the above code some more (maybe replacing the if/else with a try/except IndexError, but what's important is its correctness.

Secondary considerations

You may want to use a new-style class, so instead of

class DataPoint:

you'd do

class DataPoint(object):

Also, you can drop the initial 0 in your list slicing, as lst[:41] is identical to lst[0:41] for pretty much all intents and purposes.


when the list contains integers, but I'm in a situation where I have instances from a Class and I need them summed.

The key is understanding that you don't want to sum the class instances (that would first require defining addition of two class instances), but of some freq member of each. Therefore, we request that sum: the sum of the .freq of each given instance of the list of instances. If we accept that we'll need to give a temporary name to the instances of the list (so that we can access .freq), then the corresponding Python code reads as clearly as possible (see GaretJax's answer).

Your syntax requests the .freq of the sub-list, which of course doesn't exist.

0

精彩评论

暂无评论...
验证码 换一张
取 消