【问题标题】:Replace All Elements in 2D List with Data from Other List - Using Unique ID - Python用其他列表中的数据替换 2D 列表中的所有元素 - 使用唯一 ID - Python
【发布时间】:2014-09-03 06:30:17
【问题描述】:

我仍然只有几个月的时间进入 python,所以请原谅丑陋的代码。我有一个由唯一 ID 组成的数据集。考虑这种 3 行的格式,每行有 3 个 ID:

zList = [[1412,2521,53522],
[52632,1342,1453],
[3413,342,25232]]

我正在尝试用一些相应的数据(名字、姓氏、州等)替换每个 ID。理想的输出如下所示:

resultList = [[Bob, Smith, Ohio, Jane, Doe, Texas, John, Smith, Alaska],
[Jim, Bob, California, Jack, White, Virginia, John, Smith, Nevada],
[Hank, Black, Kentucy, Sarah, Hammy, Florida, Joe, Blow, Mississipi]]

我意识到在结果中添加一个新维度会更简洁,因为我实际上是将每个 ID 扩展为一个新列表。我避免了这种情况,因为我认为保持平坦会更容易,而且我害怕迭代超过 2 维的任何东西!愿意考虑所有选项...

我用来匹配的数据是你所期望的:

matchData = [[1412, Bob, Smith, Ohio, lots of additional data],
[2521, Jane, Doe, Texas, Lots of Additional Data],
[3411], Jim, Black, New York, Lots of Additional Data],
[...etc...]]

这是我一直在尝试的方法:

resultList = []
for i, valz in enumerate(zList):
    for j, ele in enumerate(valz):
        check = False
        for k, valm in enumerate(matchData):
            if ele == valm[0]:
                resultList.append(valm)
                check = True
                break
        if check == False:
            print "error during rebuild"
pprint.pprint(resultList, width=400)

现在虽然它几乎可以工作,但它缺少我无法弄清楚的 2 个关键问题。我的代码将所有内容转储到一个大列表中。我必须能够保持与原始数据集的顺序和逻辑分离。 (请记住,原始数据集是 3 行 3 个 ID)。

如果找不到匹配项,我还需要抛出错误。您可以在上面的代码中看到我的尝试,但它不能正常工作。我尝试在我的第一个 if 语句之后添加这个:

elif all(ele not in valm[15):
    check = False

但我收到此错误:"TypeError: argument of type 'int' is not iterable"

【问题讨论】:

  • 为什么不使用字典来匹配用户名和ID?

标签: python list multidimensional-array enumeration


【解决方案1】:

要获得更简洁的代码,您应该考虑使用类来封装数据。

让我们看看:

class Person(object):
    def __init__(self, identifier, firstname, name, state):
        self.id = identifier
        self.firstname = firstname
        self.name = name
        self.state = state

    def __repr__(self):
        return "<{0} {1} (id : {2}) living in {3}>".format(self.firstname, self.name, self.id, self.state)

    def as_list(self):
        return [self.firstname, self.name, self.state]

class PersonList(list):
    def __init__(self, *args, **kwargs):
        list.__init__(self, *args, **kwargs)

    def getById(self, identifier):
        """ return the person of this list whose the id is equals to the requested identifier. """
        # filter(boolean function, iterable collection) -> return a collection hat contain only element that are true according to the function.
        # here it is used a lambda function, a inline function declaration that say for any given object x, it return x.id == identifier.
        # the list is filtered to only get element with attribut id equals to identifier. See https://docs.python.org/3.4/library/functions.html#filter
        tmp = list(filter(lambda x: x.id == identifier, self))
        if len(tmp)==0:
            raise Exception('Searched for a Person whose id is {0}, but no one have this id.'.format(identifier))
        elif len(tmp) > 1:
            raise Exception('Searched for a Person whose id is {0}, and many people seem to share this id. id are supposed to be unique.'.format(identifier))
        return tmp[0]

##CONSTANTS##   
#id list - modified to not instanciate 9 Person
ids = [[1412,2521,3411],#bob, jane, jim
        [3411,1412,1412],#jim, bob, bob
        [3411,2521,2521]]#jim, jane, jane

#person list 
index=PersonList([Person(1412, 'Bob', 'Smith', 'Ohio'),
         Person(2521, 'Jane', 'Doe', 'Texas'),
         Person(3411, 'Jim', 'Black', 'New York')])

def computeResult(id_list, personList): 
    personList = [ [personList.getById(identifier) for identifier in subList] for subList in id_list]

    resultList= []
    for sublist in personList:
        tmp = []
        for person in sublist:
            tmp += person.as_list()
        resultList.append(tmp)

    return resultList

if __name__ == "__main__":

    print(computeResult(ids, index))

一方面,我认为代码更难编写,因为您使用了错误的数据结构。应用程序应该处理诸如 Person 对象而不是字符串列表之类的东西。无论如何,这是您的应用程序。我只是建议您考虑使用personList 作为比这个丑陋的列表更好的数据结构来处理您的数据。 另一方面,如果我认为 id 是唯一的,如果您成功地将数据放入字典中,例如

index={1412 : Person(...), 2500 : Person(...), ...}

index={1412: ['Bob', 'Doe', ...], 2500 : [...], ...}` 

这肯定会更实用,因为您可以删除 PersonList 类并仅使用 index.get(1412) 来获取与 id 对应的数据。

编辑:根据要求添加跟踪示例。

此脚本保存在名为“sof.py”的文件中

python3
>>> import sof
>>> sof.index
[<Bob Smith (id : 1412) living in Ohio>, <Jane Doe (id : 2521) living in Texas>, <Jim Black (id : 3411) living in New York>]
>>> sof.index.getById(666)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/vaisse/Bureau/sof.py", line 25, in getById
  raise Exception('Searched for a Person whose id is {0}, but no one have this id.'.format(identifier))
Exception: Searched for a Person whose id is 666, but no one have this id.

如您所见,万一出现错误,一切都会停止。如果此行为不是您想要的行为,您还可以例如返回一个None 值并在某处跟踪失败而不是上升Exception,然后继续处理数据。如果您希望您的应用程序在出现错误的情况下仍能运行,您应该查看https://docs.python.org/3.1/library/warnings.html。否则简单的异常引发就足够了

【讨论】:

  • 我会看看这个。我喜欢在错误中引发异常的能力。原始列表可能包含数百个“3 组”,因此了解尝试匹配时是否出现错误非常重要。想知道您是否可以发布示例输出?
【解决方案2】:

我认为您的主要问题是构建列表。从它的外观来看,zList 中的每行和 resultList 中的每行都有 3 个“条目”。我建议将 zList 更改为一维列表,并将结果列表中的不同条目放在它自己的列表中(在 resultList 中像这样:

zList = [ 1412, 2521, 53522, 52632, 1342, 1453, 3413, 342, 25232 ]
resultList = [[ "Bob", "Smith", "Ohio" ],[ "Jane", "Doe", "Texas" ],[ "John", "Smith", "Alaska" ],
          [ "Jim", "Bob", "California" ],[ "Jack", "White", "Virginia" ],[ "John", "Smith", "Nevada" ],               
          [ "Hank", "Black", "Kentucy" ],[ "Sarah", "Hammy", "Florida" ],[ "Joe", "Blow", "Mississipi"]]

现在您可以检查两个列表的长度是否相同(在本例中为 9):

>>> len(zList) == len(resultList
True
>>> len(zList)
9

从这里,您可以使用字典或列表。作为新手程序员,你可能还不熟悉字典,请查看the documentation

列表:

只需遍历列表的长度,将其添加到新列表中,然后将该新列表附加到您的输出列表中,如下所示:

zList = [...]
resultList = [[...]]
matchList = [] #or whatever you want to call it

for i in range(len(zList)): #the index is needed, you can also use enumerate
    element_list = []
    element_list.append(zList[i]) #note zList[i] = 2nd iterator of enumerate
    for j in resultList[i]:  #the index is not needed, so use the value 
        element_list.append(j)
    matchList.append(elementList)

>>> print matchList
[1412, 'Bob', 'Smith', 'Ohio']
[2521, 'Jane', 'Doe', 'Texas']
[53522, 'John', 'Smith', 'Alaska']
[52632, 'Jim', 'Bob', 'California']
[1342, 'Jack', 'White', 'Virginia']
[1453, 'John', 'Smith', 'Nevada']
[3413, 'Hank', 'Black', 'Kentucy']
[342, 'Sarah', 'Hammy', 'Florida']
[25232, 'Joe', 'Blow', 'Mississipi'] #split in separate lines for clarity here

要添加更多数据,只需增加 resultList 中列表的大小,这样您就可以添加如下作业:

resultList = [[ "Bob", "Smith", "Ohio", "Tech Support" ], ...

字典

我认为这是更简单的方法。只需创建一个字典,然后使用 zList 中的元素与 resultList 中的相应元素形成键,如下所示:

matchDict = {}
for n in range(len(zList)): #need the index, remember?
    matchDict[zList[n]] = resultList[n]

>>> print matchDict
{ 1412 : ['Bob', 'Smith', 'Ohio'] ,
  1453 : ['John', 'Smith', 'Nevada'] ,
  25232 : ['Joe', 'Blow', 'Mississipi'] ,
  53522 : ['John', 'Smith', 'Alaska'] ,
  3413 : ['Hank', 'Black', 'Kentucy'] ,
  342 : ['Sarah', 'Hammy', 'Florida'] ,
  52632 : ['Jim', 'Bob', 'California'] ,
  2521 : ['Jane', 'Doe', 'Texas'] ,
  1342 : ['Jack', 'White', 'Virginia']  }

*注意,您可以使用字典中的键调用元素,因此打印 matchDict[1412] -> ["Bob", "Smith", "Ohio"]。同样,您可以通过向 resultList 添加更多信息来扩展数据,如上所示。

【讨论】:

  • 这很有帮助,但我保留与原始 zList 的逻辑分离非常重要。即:(来自第 1 组的 bob、jane 和 john),(来自第 2 组的 jim、jack 和 john)。我不确定您的回答是否考虑到这一点?
猜你喜欢
  • 2020-03-29
  • 1970-01-01
  • 1970-01-01
  • 2023-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-13
  • 2021-08-24
相关资源
最近更新 更多