如何将项目添加到具有扩展值的多维数组

How to add items to multi-dimensional arrays with expanding values

我正在做一个项目,我有一个包含名称、货币价值等的列表列表。我 运行 在尝试更新主列表中的各个子列表时遇到了麻烦当用户输入一个值。

例如,我的列表包含 4 行(常量)和基于用户条目的不确定列数。我包含整个程序仅供参考,以防对它的外观有疑问:

spacing = '- ' * 45  # formatting for DONOR header
data_list = [['NAMES', 'DONATION AMOUNT', 'Number of Gifts', 'Avg Gifts'],
         ['Rudolph S', 1500, 3, 0],  
         ['Josef M', 250, 5, 0],
         ['Joye A', 5000, 2, None],
         ['Joni M', 2750, 1, None],
         ['Rachelle L', 750, 3, None],
         ['Vena U', 1000, 7, None],
         ['Efrain L', 10000, 1, None],
         ['Mee H', 15000, 2, None],
         ['Tanya E', 50000, 1, None],
         ['Garrett H', 800, 2, None]] 

def addtolist():
"""Method for sending 'Thank You' messages to Donors, using names *"""

    while True:
        print("Enter the name of the person you are writing to (or enter 'list' to see a list of names or Q to quit) ")
        fname_prompt = input("First Name: ").strip().capitalize()
        if fname_prompt.upper() == "Q":
            break
        elif fname_prompt.lower() == "list":  
            if len(data_list) - 1 % 2 != 0:
                for i in range(0, int(len(data_list) - 1 / 2)):
                    cut_off = int((len(data_list)) / 2)
                    if i == 0:               
                        print(spacing)
                        print('{:>44s}'.format(str(data_list[i][0])))  
                        print(spacing)
                    elif cut_off + i >= len(data_list):
                        continue
                    else:
                        print('{:>30s}'.format(data_list[i][0]), '{:>35s}'.format(data_list[cut_off + i][0]))
            else:
                if i == 0:                                                  
                    print(spacing)
                    print('{:>20s}'.format(str(data_list[i])))              
                    print(spacing)
                else:
                    print('{:>15s}'.format(data_list[i][0]), '{:>30s}'.format(data_list[cut_off + i][0]))
        else:
            lname_prompt = input("Last Name: ").strip().capitalize()
            if lname_prompt.upper() == "Q":
                break
            elif lname_prompt.lower() == "list":
                if len(data_list) - 1 % 2 != 0:
                    for i in range(0, int(len(data_list) - 1 / 2)):
                        cut_off = int((len(data_list)) / 2)
                        if i == 0:                                          
                            print(spacing)
                            print('{:>44s}'.format(str(data_list[i][0])))  
                            print(spacing)
                        elif cut_off + i >= len(data_list):
                            continue
                        else:
                            print('{:>30s}'.format(data_list[i][0]), '{:>35s}'.format(data_list[cut_off + i][0]))
                else:
                    if i == 0:  # for each item in list / 2 (5 x)
                        print(spacing)
                        print('{:>20s}'.format(str(data_list[i][0])))  
                        print(spacing)
                    else:
                        print('{:>15s}'.format(data_list[i][0]), '{:>30s}'.format(data_list[cut_off + i][0]))
            else:
                full_name = fname_prompt + " " + lname_prompt
                if full_name != "List List" or full_name != "list ":
                    name_found = False
                    for vals in data_list:
                        if full_name in vals:
                            name_found = True
                        else:
                            name_found = False

                        if name_found is False:
                            add_name = input("That name is not in the Donor list. Do you want to add it to the list?  ").upper()
                            if add_name == "Y":                                         
                                data_list.append([full_name])
                                if len(data_list) - 1 % 2 != 0:
                                    for i in range(0, int(len(data_list) - (len(data_list) - 2) / 2)):
                                        cut_off = int((len(data_list)) / 2)
                                            if i == 0:                                          
                                                print(spacing)
                                                print('{:>44s}'.format(str(data_list[i][0])))
                                                print(spacing)
                                            elif cut_off + i >= len(data_list):
                                                 print('{:>30s}'.format(data_list[i][0]))
                                                continue
                                            else:
                                                print('{:>30s}'.format(data_list[i][0]), '{:>35s}'.format(data_list[cut_off + i][0]))
                                 else:
                                     if i == 0:  # for each item in list / 2 (5 x)
                                         print(spacing)
                                         print('{:>20s}'.format(str(data_list[i][0])))  
                                         print(spacing)
                                     else:
                                         print('{:>15s}'.format(data_list[i][0]), '{:>30s}'.format(data_list[cut_off + i][0]))

                             donation_amt = int(input("Enter in the donation amount from Donor {0}: $".format(full_name)))
                             print('{0} has donated '.format(full_name, donation_amt))
                             data_list.append(donation_amt) # difficulty HERE
                             print(data_list)

我遇到困难的主线在最后有评论 "difficult HERE"。

data_list.append(donation_amt) # difficulty HERE

我正在努力做到这一点,以便当用户输入新名称和新捐赠金额时(或者如果他们只是 select 现有名称并附加捐赠金额),程序可以append/insert 相关子列表的货币价值(它所附加的名称)。我现在设置它的方式只是将数值附加到较大列表的末尾,但我未能成功将值附加到子列表......以前有人做过这样的事情吗?

3 维列表可以添加到主列表或子列表之一。

data_list.append(donation_amt)

会附加到主列表,这意味着如果您有一个像您这样的列表,它会添加到最后。

[['NAMES', 'DONATION AMOUNT', 'Number of Gifts', 'Avg Gifts'],
     ['Rudolph S', 1500, 3, 0],  
     ['Josef M', 250, 5, 0],
     ['Joye A', 5000, 2, None],
     ['Joni M', 2750, 1, None],
     ['Rachelle L', 750, 3, None],
     ['Vena U', 1000, 7, None],
     ['Efrain L', 10000, 1, None],
     ['Mee H', 15000, 2, None],
     ['Tanya E', 50000, 1, None],
     ['Garrett H', 800, 2, None],
      [donation_amt]]

如果您想将捐赠金额添加到特定索引,请使用

data_list[index].append(donation_amt).

如果这不起作用或者您想要更好的解释,请告诉我,这可能是另一个问题。

您似乎有 4 个静态列和不确定的行数。

您是否考虑过使用字典列表,例如 json 文档?

    data_list = [{
            'NAME':'Rudolph S',
            'DONATION AMOUNT' : 1500,
            'Number of Gifts' : 3,
            'Avg Gifts' :  0
        },{
            'NAME':'Josef M',
            'DONATION AMOUNT' : 250,
            'Number of Gifts' : 5,
            'Avg Gifts' :  None
        }]

等等。如果您可以引用各个键并更新它们的值,而不是使用列表和索引值,我认为您可能会更轻松地处理数据。

为了将donation_amt正确地附加到正确的子列表中,您需要首先确定捐赠者所属列表中的索引。找到索引后,您可以将捐赠金额附加到该索引处的子列表。为此,替换:

data_list.append(donation_amt) # difficulty HERE

与:

# Determine index where the donor belongs
idx = -1
for item in range(0, len(data_list)):
    if data_list[item][0] == full_name:
        idx = item
        break

# Append to the sublist
data_list[idx].append(donation_amt)

我试过了,它对我有用。

Two-dimensional Python 中的列表仅仅是列表的列表。因此,data_list 的每个元素本身就是一个列表。这是访问元素的示例,第一个元素位于 headers 行下方(因此,索引为 1):

>>> first_entry = data_list[1]
>>> first_entry
['Rudolph S', 1500, 3, 0]

由于 data_list[1](我们将其存储为一个名为 first_entry 的变量)也是一个我们可以访问的列表,我们可以访问第四个元素(在索引 3 处,因为列表开始索引于0) 的第一个条目如下:

>>> first_entry = data_list[1]
>>> fourth_element = first_entry[3]
>>> fourth_element
0

或者,更简洁:

>>> data_list[1][3]
0

因此,要开始回答您的问题,如果您的目标是更新 "Joye A" 的捐赠金额,您将使用 data_list[3][1] = donation_amt。这是因为 Joye 的条目位于主列表的索引 3,而捐款记录在她的子列表的索引 1。

不幸的是,这并不能真正解决您的问题,因为您想使用任意名称来创建新条目或更新现有条目。这里真正的答案是你使用了错误的数据结构。不过,出于教育价值的考虑,我将继续介绍如何使用现有结构执行此操作。

使用矩阵

首先您需要确定该名称是否已经存在。因此,最好创建一个额外的列表,其中 仅包含 第一列,一个一维列表。您可以通过多种方式执行此操作。我会将其显示为列表理解:

>>> names_only = [e[0] for e in data_list]
>>> names_only
['NAMES', 'Rudolph S', 'Josef M', ...]

我不会在这里解释这一点,但是有很多线程向不了解列表推导式的读者解释列表推导式的工作原理。

首先,您检查该名称是否已存在于矩阵中:

>>> 'Josef M' in names_only
True

如果是这样,您现在需要找到您要查找的名称的索引。 Python 中的列表具有索引函数:

>>> idx = names_only.index('Joesf M')
>>> idx
2

您现在按上述更新他的捐款金额:

>>> data_list[idx][1] = donation_amt

现在,如果他不在矩阵中,我们要创建一个全新的行。假设我们正在处理一个名为 'bob' 的用户。他还没有进入矩阵。在这里你使用你的追加函数:

>>> data_list.append([bob, donation_amt, 1, None])

其中 1None 可以替换为您的默认值。将它们作为一个函数放在一起:

>>> def update_or_create(name, amt):
...   names = [e[0] for e in data_list]
...   if name in names:
...      idx = names.index(name)
...      data_list[idx][1] = amt
...   else:
...      data_list.append([name, amt, 1, None])

应该按照你的要求去做。

终于

为此使用不同的结构会更好。我会提出一个像这样的字典结构:

new_structure = {NAME: {'donation': DONATION_AMT, 'num_gifts': NUM_GIFTS, 'avg_amt': AVERAGE_DONATION},...}

无需赘述,遵循此格式将允许以下函数执行相同的任务:

>>> def update_or_create(name, amt):
...   if name in new_structure:
...       new_structure[name]['donation'] = amt
...   else:
...       new_structure.update({name: {'donation': amt, 'num_gifts': 1, 'avg_amt': None}})

好多了。