2017-09-19 21 views
8

Tôi đang tiêu thụ một số điểm cuối của một API rất chi tiết trong dữ liệu mà nó trả về. Tôi muốn cung cấp một tập con của dữ liệu này cho một đoạn mã khác ở nơi khác.Cách che dấu một từ điển lồng nhau Python 3 để trả về một từ điển mới chỉ với một số mục nhất định?

Giả sử tôi đưa ra nhiều từ điển như thế này (mà tôi có kế hoạch để lặp qua và lọc):

asset = { 
    'id': 1, 
    'name': 'MY-PC', 
    'owner': 'me', 
    'location': 'New York City', 
    'model': { 
     'id': 1, 
     'name': 'Surface', 
     'manufacturer': { 
      'id': 1, 
      'name': 'Microsoft' 
     } 
    } 
} 

Tôi muốn tạo ra một chức năng mà sẽ mất rằng từ điển trong, cùng với một "mặt nạ" mà sẽ được sử dụng để tạo một từ điển mới chỉ cho các mục được phép. Đây có thể là một ví dụ mặt nạ (tuy nhiên, tôi có thể làm việc với bất cứ định dạng làm cho mã kết quả các ngắn gọn nhất):

mask = { 
    'id': True, 
    'name': True, 
    'model': { 
     'id': True, 
     'name': True, 
     'manufacturer': { 
      'name': True 
     } 
    } 
} 

Các chức năng nên sau đó trở về này:

mask = { 
    'id': 1, 
    'name': 'MY-PC', 
    'model': { 
     'id': 1, 
     'name': 'Surface', 
     'manufacturer': { 
      'name': 'Microsoft' 
     } 
    } 
} 

Có một cái gì đó đã được xây dựng vào Python 3 có thể trợ giúp trong việc này? Có vẻ như tôi phải làm điều này bằng tay, nó sẽ trở nên khá xấu xí một cách nhanh chóng. Tôi tìm thấy itertools.compress, nhưng điều đó có vẻ như nó dành cho danh sách và sẽ không xử lý sự phức tạp của từ điển.

+0

Bạn đã nghe nói về ['jq (1)'] (https://stedolan.github.io/jq/) chưa? – o11c

+0

ywhat nên xảy ra khi các phím mặt nạ không có khóa dữ liệu phù hợp? –

Trả lời

3

Bạn đệ quy có thể xây dựng một dict mới từ mặt nạ bằng cách chọn chỉ có giá trị tương ứng trong chính dict:

def prune_dict(dct, mask): 
    result = {} 
    for k, v in mask.items(): 
     if isinstance(v, dict): 
      value = prune_dict(dct[k], v) 
      if value: # check that dict is non-empty 
       result[k] = value 
     elif v: 
      result[k] = dct[k] 
    return result 

print(prune_dict(asset, mask)) 

{'id': 1, 
'model': {'id': 1, 'manufacturer': {'name': 'Microsoft'}, 'name': 'Surface'}, 
'name': 'MY-PC'} 
2

Đây sẽ là một cơ hội tốt để sử dụng đệ quy, đây là một số mẫu mã tôi đã không kiểm tra:

def copy(asset, result, mask): 
    for key_name, value in mask.items(): 
     if value == True: 
      result[key_name] = asset[key_name] 
     else: 
      result[key_name] = x = {} 
      copy(asset[key_name], x, value) 

y = {} 
copy(asset, y, mask) 
0

này có lẽ sẽ là một hàm đệ quy. Ngoài ra, đối mặt nạ, tôi khuyên bạn nên định dạng này: mask = ["id", "name", "model.id", "model.name", "model.manufacturer.name"]

Sau đó, trước tiên bạn muốn giữ chỉ mục được đặt tên trong mặt nạ:

def filterstage1(dictionary, mask): 
    result = {} 
    for key in dictionary: 
     if isinstance(dictionary[key], dict): 
      newmask = [maskname[mask.find(".") + 1:] for maskname in mask if maskname.startswith(key + ".")] 
      result[k] = filterstage1(dictionary[key], newmask) 
     elif key in mask: 
      result[key] = dictionary[key] 
    return result 

Sau đó, tùy thuộc vào việc hay không bạn muốn loại bỏ tiểu từ điển mà không được trong mặt nạ và không có các bổ sung, bạn có thể bao gồm các giai đoạn thứ hai:

def filterstage2(dictionary, mask): 
    result = {} 
    for key in dictionary: 
     if not (isinstance(dictionary[key], dict) and dictionary[key] == {} and key not in mask): 
      result[key] = dictionary[key] 

mã cuối cùng: filterstage2(filterstage1(dictionary, mask), mask). Bạn có thể kết hợp hai giai đoạn với nhau nếu bạn muốn.

+0

P.S. Xem các câu trả lời khác; giải pháp này có lẽ không phải là rất tốt đẹp cho mã sản xuất: P – HyperNeutrino

Các vấn đề liên quan