2017-07-16 102 views
0

所以這是我迄今爲止的嘗試;我用一個有問題的lambda以前的答案,然後嘗試了別的東西。我的第二種方法可行,但我想知道(如果和)爲什麼效率低下。另外一個修復會很好。通過詞典列表高效排序?

people = [ 
{'name': "Tom", 'age': 10}, 
{'name': "Mark", 'age': 5}, 
{'name': "Pam", 'age': 7} 
] 

# This did not work; I got '<filter object at 0x1020b7f28>' back, which I believe is the memory location itself. 
result = filter(lambda person: person['name'] == 'Pam', people) 
print(result) 

# This is the attempt that works but looks very ugly. 
def search(name): 
    counter = 0 
    for student in people: 
     if student['name'] == name: 
      print("{0} is {1} years old.".format(student['name'], student['age'])) 
      break 
     else: 
      counter += 1 
    if counter == len(people): 
     print("There are no students with that name.") 
+5

'filter'是懶惰的,調用'tuple(...)'就可以實現它的結果。 –

+2

你的意思是「排序」或「搜索」? – Anthon

+0

你不需要保留一個人數的計數器。如果您已遍歷列表中的所有元素並未找到該名稱,則可以假定該名稱不在列表中。因此,保留一個計數器並檢查它是否等於人的長度是多餘的,有幾種不同的方法可以解決這個問題,但不是使用「break」,而是從if語句中返回,並將打印語句保留在for循環原始。 – Erich

回答

0

返回true,當你發現其他人返回False,或者你可以返回名或無

def search(name): 
    counter = 0 
    for student in people: 
     if student['name'] == name: 
      print("{0} is {1} years old.".format(student['name'], student['age'])) 
      return True 

    return False 

在重複的名稱返回列表或元組的情況

def search(name): 
    name_list=[] 
    for student in people: 
     if student['name'] == name: 
      print("{0} is {1} years old.".format(student['name'], student['age'])) 
      name_list.append((student['name']) 

    return name_list 
-1

我相信,每個條目它是自己的對象,因爲列表只存儲指向字典的指針。正因爲如此,你不能真正知道該列表是否包含O(1)時間的名稱,所以至少需要O(n)。

如果你想使用更多的內存,你可以存儲一組名稱,但這只是一個快速包含,而不是一個快速訪問。這個用例就是很多不存在的查詢。

如果你能夠修改數據類型,我會建議使用字典詞典,其中的關鍵是每個人的名字。這允許您在O(1)時間訪問目標人員的信息。

例如

my_dict = { 
"Edward":{"age":10} 
"Gerald":{"age":54} 
"Rashim":{"age":23} 
} 

,然後讓你做這樣的事情:

my_dict["Rashim"]["age"] 
>23 

否則,我認爲您的解決方案是好的,O(n)的時間。

+0

這假定沒有重複的名稱,並修改原始輸入。 –

+0

是的,我提到過。 – Erich

1

您不需要明確的計數器變量。你知道,如果你達到你最終沒有找到匹配的名稱,所以只print()有:

def search(name): 
    for student in people: 
     if student['name'] == name: 
      print("{0} is {1} years old.".format(student['name'], student['age'])) 
      return 
    print("There are no students with that name.") 

注意,這個解決方案仍然會爲O(n) - 與您的原版的。作爲@Erich提到的,如果你想有一個解決方案,這將是O(1),使用字典映射每個人的名字,以自己的特定屬性:

>>> people = { 
'Tom': {'age': 10}, 
'Mark': {'age': 5}, 
'Pam': {'age': 7} 
} 
>>> def search(name): 
    person = people.get(name, None) 
    if person is not None: 
     print("{0} is {1} years old.".format(name, person['age'])) 
    else: 
     print("There are no students with that name.") 


>>> search('Bobby') 
There are no students with that name. 
>>> search('Mark') 
Mark is 5 years old. 
>>> search('Timmy') 
There are no students with that name. 
>>> 
+0

總是不能假定名稱是唯一的,但是這個解決方案仍然使得搜索O(1)。 – Afaq

+0

@Afaq真。這是一個有效的點。如果用戶名稱重複,則此解決方案無法工作。 –

1

整個方法可以概括爲:

def search(name): 
    try: 
     student = next(i for i in people if i['name'] == name) 
     print("{0} is {1} years old.".format(student['name'], student['age'])) 
     return True 
    except StopIteration: 
     return False 
+0

這是加速的最佳答案。我會添加一個附錄:如果您希望多個條目共享一個「名稱」屬性,您可能想要做一個列表理解而不是僅僅保留第一個元素。 – Erich

1

首先,你原來的嘗試實際上並工作,它只是返回一個generator而不是一個列表。這樣做的原因是,過濾器可以被懶惰地評估(即,直到你嘗試迭代它才能完成工作)。以下內容將按照您的預期工作。

result = list(filter(lambda person: person['name'] == 'Pam', people)) 

不過,我認爲它可以因爲你似乎想它評估使用列表理解,而不是過濾器來改善一下。

result = [person for person in people if person.name == 'Pam']