簡體   English   中英

Python:將列表鏈接在一起

[英]Python: Linking Lists Together

假設我有一個列表,其中每個索引要么是一個名稱,要么是先前名稱索引保留的房間列表。

[["Bob"],["125A, "154B", "643A"],["142C", "192B"], ["653G"], 
["Carol"], ["95H", 123C"], ["David"], ["120G"]]

因此,在這種情況下,Bob保留了以下房間:125A,154B,643A,152C,192B和653G,等等。

如何構造一個函數,將上述內容轉換為以下格式:

[["Bob", "125A, "154B", "643A", "142C", "192B", "653G"], ["Carol"... 

本質上將[名稱]與所有[房間預訂列表]連接起來,直到[名稱]的下一個實例。 我有一個接受列表的函數 ,如果列表是名稱,則返回True ,如果是房間預訂列表,則返回False ,所以有效地我擁有:

上面列出的內容為[True, False, False, False, True, False, True False] ,但不確定(如果有)對我有什么幫助。 假設一個列表包含名稱,那么它只有一個名稱。

給出以下方法

def is_name(x):
  return # if x is a name or not

一個簡單而簡短的解決方案是使用defaultdict


例:

from collections import defaultdict

def do_it(source):
  dd = defaultdict(lambda: [])
  for item in sum(source, []): # just use your favourite flattening method here
    if is_name(item):
      name = item
    else:
      dd[name].append(item)
  return [[k]+v for k,v in dd.items()]

for s in do_it(l):
  print s

輸出:

['鮑勃','125A','154B','643A','142C','192B','653G']
['Carol','95H','123C']
['David','120G']


獎金:

這個使用發電機懶惰

import itertools 

def do_it(source):
  name, items = None, []
  for item in itertools.chain.from_iterable(source):
    if is_name(item):
      if name: 
        yield [name] + items
        name, items = None, []
      name = item
    else:
      items.append(item)
  yield [name] + items

首先,我將非常同意@uʍopǝpısdn的建議。 但是,如果您的設置由於某種原因而無法更改它,那么這似乎可以工作(盡管效果不佳):

# Original list
l = [["Bob"],["125A", "154B", "643A"],["142C", "192B"], ["653G"], ["Carol"], ["95H", "123C"], ["David"], ["120G"]]
# This is the result of your checking function
mapper = [True, False, False, False, True, False, True, False]

# Final list
combined = []

# Generic counters
# Position in arrays
i = 0
# Position in combined list
k = 0

# Loop through the main list until the end.
# We don't use a for loop here because we want to be able to control the
# position of i.
while i < len(l):
  # If the corresponding value is True, start building the list
  if mapper[i]:
    # This is an example of how the code gets messy quickly
    combined.append([l[i][0]])
    i += 1
    # Now that we've hit a name, loop until we hit another, adding the
    # non-name information to the original list
    while i < len(mapper) and not mapper[i]:
      combined[k].append(l[i][0])
      i += 1

    # increment the position in our combined list
    k += 1


print combined

假設獲取列表並根據列表包含名稱還是房間返回True或False的函數稱為containsName()...

def process(items):
  results = []
  name_and_rooms = []
  for item in items:
    if containsName(item):
      if name_and_rooms:
        results.append(name_and_rooms[:])
        name_and_rooms = []
      name_and_rooms.append(item[0])
    else:
      name_and_rooms.extend(item)
  if name_and_rooms:
    results.append(name_and_rooms[:])
  return results

即使沒有要遵循的房間列表,也將打印出名稱,例如[['bob'],['susan']]。

同樣,這不會合並重復的名稱,例如[['bob'],['123'],['bob'],['456']]。 如果需要的話,則需要將名稱推送到一個臨時字典中,並將每個房間列表作為它的值。 然后最后吐出字典的鍵值。 但這本身不會保留名稱的順序。 如果您希望保留名稱的順序,則可以使用另一個包含名稱順序的列表,並在將dict中的值吐出時使用該列表。

確實,您應該為此使用dict 這假定列表的順序不變(名稱始終是第一)。

正如其他人建議的那樣,您應該重新評估數據結構。

>>> from itertools import chain
>>> li_combo = list(chain.from_iterable(lst))
>>> d = {}
>>> for i in li_combo:
...    if is_name(i):
...       k = i
...    if k not in d:
...       d[k] = []
...    else:
...       d[k].append(i)
... 
>>> final_list = [[k]+d[k] for k in d]
>>> final_list
[['Bob', '125A', '154B', '643A', '142C', '192B', '653G'], ['Carol', '95H', '123C'], ['David', '120G']]

減少是您的答案。 您的數據是這樣的:

l=[['Bob'], ['125A', '154B', '643A'], ['142C', '192B'], ['653G'], ['Carol'], ['95H', '123C'], ['David'], ['120G']]

您說您已經有了一個確定元素是否為名稱的函數。 這是我的:

import re
def is_name(s):
  return re.match("[A-z]+$",s) and True or False

然后,使用reduce,它是一個襯里:

reduce(lambda c, n: is_name(n[0]) and c+[n] or c[:-1]+[c[-1]+n], l, [])

結果是:

[['Bob', '125A', '154B', '643A', '142C', '192B', '653G'], ['Carol', '95H', '123C'], ['David', '120G']]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM