2010-11-16 48 views
7

Tôi có một dict rằng có rất nhiều yếu tố, tôi muốn viết một chức năng mà có thể trở lại các yếu tố trong phạm vi chỉ số nhất định (điều trị dict như mảng):python: làm thế nào để có được một tập hợp con của dict

get_range(dict, begin, end): 
    return {a new dict for all the indexes between begin and end} 

Làm thế nào có thể được thực hiện?

EDIT: Tôi không yêu cầu sử dụng bộ lọc quan trọng ... ví dụ)

{"a":"b", "c":"d", "e":"f"} 

get_range(dict, 0, 1) returns {"a":"b", "c":"d"} (the first 2 elements) 

Tôi không quan tâm việc phân loại ... Thật sự tôi đang thực hiện phân trang phía máy chủ ...

+2

bởi __indexes__ bạn có nghĩa là khóa ??? – mouad

+1

@singularity: Nhìn vào câu hỏi trong quá khứ của OP http://stackoverflow.com/questions/4181367/python-possible-to-filter-dict bạn nên nói đúng. – kennytm

+0

KHÔNG, không phải bằng phím, chỉ sau khi sắp xếp (hoặc không phân loại gì cả), tôi muốn phần đầu/cuối/giữa của dict ... –

Trả lời

16

Chỉnh sửa: Từ điển là không được đặt hàng. Không thể làm cho get_range trả về cùng một lát bất cứ khi nào bạn đã sửa đổi từ điển. Nếu bạn cần kết quả xác định, hãy thay thế dictwith a collections.OrderedDict của bạn.

Dù sao, bạn có thể nhận được một lát using itertools.islice:

import itertools 
def get_range(dictionary, begin, end): 
    return dict(itertools.islice(dictionary.iteritems(), begin, end+1)) 

Câu trả lời trước đó lọc bằng phím được giữ dưới đây:

Với @Douglas 'thuật toán, chúng ta có thể đơn giản hóa nó bằng cách sử dụng biểu thức trình tạo:

def get_range(dictionary, begin, end): 
    return dict((k, v) for k, v in dictionary.iteritems() if begin <= k <= end) 

BTW, không sử dụng dict làm tên biến, như bạn có thể thấy ở đây dict là một hàm tạo của từ điển.

Nếu bạn đang sử dụng Python 3.x, bạn có thể sử dụng tính năng đọc hiểu từ điển trực tiếp.

def get_range(dictionary, begin, end): 
    return {k: v for k, v in dictionary.items() if begin <= k <= end} 
+0

Giải pháp tốt và vẫn rất dễ đọc. – helpermethod

+0

Gọi biến the_dict hoặc như vậy là kiểu "thích hợp" cho các biến. –

+0

@Chris: OK. (Đổi tên thành 'dictionary' để cả hai bên đều vui vẻ :)) – kennytm

3

Straight thực hiện về phía trước:

def get_range(d, begin, end): 
    result = {} 
    for (key,value) in d.iteritems(): 
     if key >= begin and key <= end: 
      result[key] = value 
    return result 

Một dòng:

def get_range2(d, begin, end): 
    return dict([ (k,v) for (k,v) in d.iteritems() if k >= begin and k <= end ]) 
+2

hoặc: __begin <= key <= end__ – mouad

+1

Eek, * vui lòng * không gọi tham số 'dict' ... cũng' key> = bắt đầu và khóa <= end' sẽ là neater là 'begin <= key < = kết thúc'. Tính năng Python mát mẻ, cách bạn có thể làm điều đó. –

+0

Chỉ cần theo OP ... Tôi đồng ý với tên biến xấu. –

0

nghỉ ngơi yên tâm rằng những gì bạn thực sự muốn có một OrderedDict, bạn cũng có thể sử dụng enumerate:

#!/usr/bin/env python 
def get_range(d, begin, end): 
    return dict(e for i, e in enumerate(d.items()) if begin <= i <= end) 

if __name__ == '__main__': 
    print get_range({"a":"b", "c":"d", "e":"f"}, 0, 1) 

đầu ra:

{'a': 'b', 'c': 'd'} 

ps: Tôi cho phép bạn sử dụng 0, 1 như các giá trị phạm vi, nhưng bạn nên sử dụng 0, 2 để ký "hai phần tử đầu tiên" (và sử dụng begin <= i < end làm hàm so sánh

0

Như những người khác đã đề cập, trong từ điển Python vốn đã không có thứ tự. Tuy nhiên, tại bất kỳ thời điểm nào, danh sách các khóa hiện tại hoặc các cặp khóa, giá trị có thể thu được bằng cách sử dụng các phương thức keys() hoặc items() của chúng.Một vấn đề có thể xảy ra khi sử dụng các danh sách này không chỉ là nội dung của chúng mà cả thứ tự nó được trả về sẽ thay đổi nếu từ điển đã được sửa đổi (hoặc biến đổi) kể từ lần cuối cùng chúng được sử dụng. Điều này có nghĩa là bạn thường không thể lưu trữ và sử dụng lại danh sách trừ khi bạn cập nhật nó mỗi khi từ điển được thay đổi chỉ trong trường hợp bạn sẽ cần nó.

Để làm cho phương pháp này dễ quản lý hơn, bạn có thể kết hợp từ điển và danh sách phụ vào lớp dẫn xuất mới, đồng thời cung cấp phương thức get_range() sử dụng nội dung hiện tại của danh sách. Dưới đây là mã mẫu cho biết cách thực hiện điều này. Nó dựa trên ý tưởng tôi nhận được từ mã số trong this ActiveState Python Recipe.

class dict_with_get_range(dict): 
    def __init__(self, *args, **kwrds): 
     dict.__init__(self, *args, **kwrds) 
     self._list_ok = False 

    def _rebuild_list(self): 
     self._list = [] 
     for k,v in self.iteritems(): 
      self._list.append((k,v)) 
     self._list_ok = True 

    def get_range(self, begin, end): 
     if not self._list_ok: 
      self._rebuild_list() 
     return dict(self._list[i] for i in range(begin,end+1)) 

def _wrapMutatorMethod(methodname): 
    _method = getattr(dict, methodname) 
    def wrapper(self, *args, **kwrds): 
     # Reset 'list OK' flag, then delegate to the real mutator method 
     self._list_ok = False 
     return _method(self, *args, **kwrds) 
    setattr(dict_with_get_range, methodname, wrapper) 

for methodname in 'delitem setitem'.split(): 
    _wrapMutatorMethod('__%s__' % methodname) 
for methodname in 'clear update setdefault pop popitem'.split(): 
    _wrapMutatorMethod(methodname) 
del _wrapMutatorMethod # no longer needed 

dct = dict_with_get_range({"a":"b", "c":"d", "e":"f"}) 
print dct.get_range(0, 1) 
# {'a': 'b', 'c': 'd'} 
del dct["c"] 
print dct.get_range(0, 1) 
# {'a': 'b', 'e': 'f'} 

Ý tưởng cơ bản là để lấy được một lớp mới từ dict rằng cũng có một danh sách nội dung nội bộ để sử dụng theo phương pháp mới get_range() nó quy định rằng đối tượng từ điển thông thường thì không. Để giảm thiểu nhu cầu cập nhật (hoặc thậm chí tạo) danh sách nội bộ này, nó cũng có một lá cờ cho biết danh sách có được cập nhật hay không và chỉ kiểm tra nó và xây dựng lại danh sách khi cần thiết.

Để duy trì cờ, mỗi phương pháp từ điển kế thừa có khả năng thay đổi (hoặc biến đổi) nội dung của từ điển được "gói" với chức năng trợ giúp, đặt lại cờ và sau đó xâu thành phương pháp từ điển thông thường để thực sự thực hiện thao tác. Việc cài đặt chúng vào lớp chỉ đơn giản là đặt tên của các phương thức vào một trong hai danh sách và sau đó chuyển chúng một lần vào một tiện ích phụ trợ ngay sau khi tạo lớp.

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