用其他列表中的数据替换2D列表中的所有元素 - 使用唯一ID - Python

时间:2014-09-03 06:30:17

标签: python list multidimensional-array enumeration

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

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)

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

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

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

但是我收到了这个错误:"TypeError: argument of type 'int' is not iterable"

2 个答案:

答案 0 :(得分:0)

我认为你的主要问题是构建列表。从它看起来,你有3"条目" zList中的每行和resultList中的每行。我建议将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" ], ...

<强>字典

我认为这是更简单的方法。只需创建一个dict,然后使用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']  }

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

答案 1 :(得分:0)

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

让我们看看:

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对象而不是string列表列表。无论如何,这是你的应用程序。我建议您考虑使用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。否则简单的异常提升就足够了