Python: суммирование экземпляров классов внутри списка - PullRequest
2 голосов
/ 03 августа 2011

Я знаком со встроенной функцией sum () для списков и использовал ее раньше, например:

sum(list1[0:41])

, когда список содержит целые числа, но я нахожусь в ситуации, когда у меня естьэкземпляры класса, и мне нужно, чтобы они суммировались.

У меня есть этот класс:

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

Все они ссылаются на числа с плавающей точкой из файла XML, и эти экземпляры позже попадают в список в моем коде.

Так, например, я хочу иметь возможность сделать что-то вроде:

sum(list[0:41].freq)

, где список содержит экземпляры класса.

Я также пытаюсь получить его в цикле, чтобы второе число в диапазоне суммы () увеличивалось каждый раз, например:

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

Кто-нибудь знает, как яможно обойти это или есть другой способ сделать это?

Спасибо!

ОБНОВЛЕНИЕ:

Спасибо за все ответы, я постараюсь предоставить что-то более конкретное, чем концептуальные вещи, которые я выложилтам сначала:

# 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

diceDictionary = {}

# 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» в примере суммирования будет любым количеством точек данных для определенной переменной.

Как только у меня появятся словари, в которых выбраны броски в цикле вывода (здесь не показано), я будуПримените его к приведенному ниже коду, чтобы сделать что-то осмысленное.

Дайте мне знать, если по-прежнему есть какая-то путаница в моем намерении.Я опробую некоторые из этих предложений, но, может быть, кто-то может разобрать их до самой простой формы, учитывая то, что я предоставил.

Спасибо!

Ответы [ 4 ]

7 голосов
/ 03 августа 2011

Вы пробовали:

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

Если вам нужна кумулятивная сумма последних элементов «i», наиболее эффективным является следующее:

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

Как уже ожидали другие авторы, плохой стиль программирования - использовать имя встроенных элементов для ваших переменных; Я заменил list на items в коде выше.

1 голос
/ 03 августа 2011

Ваш последний пример будет иметь квадратичную сложность. Намного проще было бы просто сохранить промежуточный итог:

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

Если вам не нужна промежуточная сумма для каждого элемента в списке, а только общая сумма, тогда обратитесь к ответу GaretJax , который использует sum.

Кроме того, list является встроенным типом, поэтому вы, вероятно, не хотите использовать его в качестве имени переменной (что перезапишет встроенный).

0 голосов
/ 03 августа 2011

когда список содержит целые числа, но я нахожусь в ситуации, когда у меня есть экземпляры из класса, и мне нужно, чтобы они суммировались.

Ключом является понимание того, что вы не хотите суммировать экземпляры класса (для этого сначала нужно было бы определить добавление двух экземпляров класса), но нужно добавить несколько freq членов каждого . Поэтому мы запрашиваем эту сумму: сумму .freq каждого данного экземпляра списка экземпляров. Если мы примем, что нам нужно дать временное имя экземплярам списка (чтобы мы могли получить доступ к .freq), то соответствующий код Python читается как можно более ясно (см. Ответ GaretJax).

Ваш синтаксис запрашивает .freq подсписка, который, конечно, не существует.

0 голосов
/ 03 августа 2011

Для первого варианта использования, скорее всего, подойдет что-то вроде

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

.

Но если вы все равно хотите делать кумулятивные суммы, технически вы можете просто объединить их,общая сумма будет последней общей суммой.Например,

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

, а затем cumsums[40] будет суммой частот первых 41 DataPoint с.Вы могли бы даже оптимизировать приведенный выше код еще немного (возможно, заменив if / else на try / except IndexError, но важна его правильность.

Дополнительные соображения

Возможно, вы захотите использовать класс в новом стиле, поэтому вместо

class DataPoint:

вы бы сделали

class DataPoint(object):

Кроме того, вы можете отбросить начальный 0 в списке списка, поскольку lst[:41] идентичен lst[0:41] практически во всех смыслах и целях.

...