2013-07-04 41 views
8

tôi có một danh sách như đưa ra dưới đây -Python Tạo một từ điển động từ danh sách các phím

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
value1 = "Roger" 

Làm thế nào tôi có thể tạo ra từ điển năng động có thể được lấy ra như dưới đây -

mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value 

Các danh sách có thể là bất cứ điều gì; Chiều dài biến hoặc bao gồm "N" số yếu tố chưa biết đến tôi ...

Bây giờ tôi có một danh sách khác, vì vậy mà từ điển của tôi nên được cập nhật phù hợp

keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
value2 = 25 

ví dụ: Nếu Keys "Person", "Nam", "Boy", "Sinh viên", "id_123" đã tồn tại, chìa khóa mới "tuổi" nên được nối thêm ...

+0

tôi sẽ đề nghị để thêm tất cả các mục trong danh sách và sử dụng chuỗi kết quả như chìa khóa. Nó sẽ dễ dàng hơn nhiều. – rajpy

+0

Câu trả lời cho câu hỏi này có thể giúp: http://stackoverflow.com/questions/16384174/more-pythonic-way-of-counting-things-in-a-heavily-nested-defaultdict – dg123

Trả lời

8

Tôi chỉ học python, vì vậy mã của tôi có thể không phải là rất pythonic, nhưng đây là mã của tôi

d = {} 

keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
value1 = "Roger" 
value2 = 3 

def insert(cur, list, value): 
    if len(list) == 1: 
     cur[list[0]] = value 
     return 
    if not cur.has_key(list[0]): 
     cur[list[0]] = {} 
    insert(cur[list[0]], list[1:], value) 

insert(d, keyList1, value1) 
insert(d, keyList2, value2) 

{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 3, 'Name': 'Roger'}}}}}} 
+0

Điều này kết thúc khá giống với giải pháp của tôi. Một gợi ý đơn giản: tránh '.has_key' bất cứ khi nào có thể; thích 'nhanh hơn và dễ hiểu hơn' nếu danh sách [0] không nằm trong lề'. – nneonneo

+0

cảm ơn, tôi đồng ý rằng nó dễ đọc hơn và dễ đọc hơn, nhưng tại sao nó lại nhanh hơn? –

+1

Dùng thử 'timeit'. Trên máy tính của tôi, 'in' nhanh gấp hai lần' .has_key' (0.0672µs so với 0.117µs). '.has_key' là một phương pháp tra cứu, trong khi' in' là một nội trang được gửi đi nhanh hơn nhiều. – nneonneo

-2
>>> mydict = {} 
>>> keyList1 = ["Person", "Male", "Boy", "Student", "id_123", "Name"] 
>>> value1 = "Roger" 
>>> reduce(lambda x, y: x.setdefault(y, {}), keyList1, mydict) 
{} 
>>> mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] = value1 

Bạn cũng có thể làm điều đó chỉ trong một bước như

này
>>> keyList2 = ["Person", "Male", "Boy", "Student", "id_123", "Age"] 
>>> value2 = 25 
>>> reduce(lambda x,y: x.setdefault(y,{}), keyList2[:-1], mydict).update({keyList2[-1]: value2}) 
+0

>>> mydict {' Người ': {' Nam ': {' Boy ': {' Sinh viên ': {' id_123 ': {' Tên ':' Roger '}}}}}} –

+0

@AbhishekKulkarni, er .. where does' reduce (lambda x, y: x.setdefault (y, {}), keyList1, mydict) 'phụ thuộc vào số lượng phần tử hoặc các khóa cụ thể? –

1

Tạo lớp riêng của bạn bắt nguồn từ dict nơi init phương pháp có một danh sách và một giá trị duy nhất làm đầu vào và lặp qua danh sách thiết lập các khóa để định giá, xác định phương thức cập nhật lấy danh sách và giá trị mới và cho mỗi mục chưa phải là khóa đặt giá trị mới, (giả sử đó là những gì bạn cần) .

Hãy quên đi ý tưởng của

mydict [ "Person"] [ "Nam"] [ "Boy"] [ "Student"] [ "id_123"] [ "name"] = value1`

vì nó là khó hiểu với subindexes.

4

Bạn có thể làm điều này bằng cách làm lồng nhau defaultdict s:

from collections import defaultdict 

def recursive_defaultdict(): 
    return defaultdict(recursive_defaultdict) 

def setpath(d, p, k): 
    if len(p) == 1: 
     d[p[0]] = k 
    else: 
     setpath(d[p[0]], p[1:], k) 

mydict = recursive_defaultdict() 

setpath(mydict, ["Person", "Male", "Boy", "Student", "id_123", "Name"], 'Roger') 

print mydict["Person"]["Male"]["Boy"]["Student"]["id_123"]["Name"] 
# prints 'Roger' 

này có lợi thế tốt đẹp của việc có thể để viết

mydict['a']['b'] = 4 

mà không nhất thiết phải sử dụng setpath helper.

Bạn có thể làm điều đó mà không đệ quy defaultdict quá:

def setpath(d, p, k): 
    if len(p) == 1: 
     d[p[0]] = k 
    else: 
     setpath(d.setdefault(p[0], {}), p[1:], k) 
0

Tôi cố gắng để đối phó với những thứ tương tự, vì vậy tôi có thể gợi ý một số hướng dẫn, nhưng một lần nữa tôi ngây thơ trong Python, vì vậy đây chỉ là một là hướng dẫn...

bạn có một danh sách các phím , vì vậy bạn chắc chắn có thể bắt đầu với một vòng lặp lặp lại cho mỗi giá trị và sau đó gán giá trị

như

for i in keylist: 
if type(keylist[i]) == dict: 
     do something 
    else: 
     keylist[i] = {} 

trong làm điều gì đó, bạn cần phải tăng i và thay đổi chỉ mục thành [i] [i + 1] và sau đó thực hiện theo cùng một cách cho đến i + n = len (danh sách phím)

0

Sử dụng tuple(keyList1) làm khóa. (bộ dữ liệu là không thay đổi và do đó có thể là khóa dict).

Bạn sẽ có một thế giới đau đầu với cách tiếp cận dict lồng nhau. (các vòng lặp lồng nhau để liệt kê, dữ liệu kế thừa khi thứ bậc cần thay đổi, v.v.).

Trên một ý nghĩ thứ hai, có lẽ bạn nên xác định một lớp người

class Person(object): 
    gender = "Male" 
    group = "Student" 
    id = 123 
    Name = "John Doe" 

sau đó sử dụng một danh sách tất cả những người và lọc với ví dụ

male_students = [s for s in ALL_PERSONS where s.gender=="Male" and s.group="Student"] 

... cho < = 10000 sinh viên bạn sẽ được tính năng suất cao.

3

lẽ bạn có thể phân lớp dict:

class ChainDict(dict): 
    def set_key_chain(self, keyList, value): 
     t = self 
     for k in keyList[:-1]: 
      t = t.setdefault(k, {}) 
     t.setdefault(keyList[-1], value) 

c = ChainDict() 
c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Name'], 'Roger') 
print c 
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Name': 'Roger'}}}}}} 

c.set_key_chain(['Person', 'Male', 'Boy', 'Student', 'id_123', 'Age'], 25) 
print c 
>>{'Person': {'Male': {'Boy': {'Student': {'id_123': {'Age': 25, 
     'Name': 'Roger'}}}}}} 
Các vấn đề liên quan