2012-01-03 31 views
9

Có cách nào \ Bạn sẽ xây dựng tương đương với python rất hữu ích collections.defaultdict?defaultdict tương đương với danh sách

Tưởng tượng sử dụng một container như:

>>> a = collections.defaultlist(0) 
>>> a[2]=7 
>>> a[4]='x' 
>>> a 
[0,0,7,0,'x'] 

UPDATE: Tôi đã thêm một follow up question để thêm nhiều hơn chức năng này xây dựng

+0

Sử dụng JavaScript 'Array' ;-) –

+0

@Josh Lee: Bạn đã đọc các thẻ chưa? Không có JavaScript chút nào-- đây là một câu hỏi Python. –

+0

Tại sao bạn muốn điều đó? –

Trả lời

10

Tôi nghĩ rằng đây sẽ là một chút bối rối để sử dụng; tuy nhiên, đây là suy nghĩ đầu tiên của tôi về cách thực hiện:

class defaultlist(list): 
    def __init__(self, fx): 
     self._fx = fx 

    def __setitem__(self, index, value): 
     while len(self) <= index: 
      self.append(self._fx()) 
     list.__setitem__(self, index, value) 

Điều này có thể gọi (tôi nghĩ đó là cách hoạt động mặc định) cho giá trị mặc định.

Khi tôi chạy:

a = defaultlist(int) 
print a 
a[2] = 7 
a[4] = 'x' 
print a 

tôi nhận được trở lại:

[] 
[0, 0, 7, 0, 'x'] 
+0

Câu hỏi dường như muốn mặc định là một giá trị. hơn một cuộc gọi (do đó, trong khía cạnh đó, khác với 'defaultdict'). Nó sẽ là tầm thường để thích ứng với bạn để phù hợp với câu hỏi (gắn thêm 'self._fx' thay vì' self._fx() '). –

+0

Bây giờ hãy thử 'a [4] = 'x''' a [2] = 7' và xem lỗi trong mã này. Dễ dàng để sửa chữa mặc dù. –

+0

@MarkRansom, nắm bắt và sửa chữa tốt. – Finn

3

Nếu tất cả bạn cần là lập chỉ mục truy cập và không cắt/nối thêm, vv, sau đó chỉ cần sử dụng defaultdict.

(nếu bạn thực sự muốn perl/js ngữ nghĩa về vấn đề này, bạn có thể phân lớp danh sách __get____set__)

2

đề nghị của tôi:

def xtend(f): 
    def wrap(self, index, *args): 
     if len(self) <= index: 
      self.extend([self._gen()] * (index - len(self) + 1)) 
     return f(self, index, *args) 
    return wrap 

class defaultlist(list): 
    def __init__(self, gen, lst = []): 
     list.__init__(self, lst) 
     self._gen = gen 

    __setitem__ = xtend(list.__setitem__) 
    __getitem__ = xtend(list.__getitem__) 

Kết quả:

>>> a = defaultlist(int, [1, 2, 3]) 
>>> a[10] = 'x' 
>>> a[2] = 7 
>>> print a 
[1, 2, 7, 0, 0, 0, 0, 0, 0, 0, 'x'] 
0

Có lẽ cách dễ nhất là sử dụng một mệnh đề:

>>> a = {} 
>>> a[2] = 7 
>>> a[4] = 'x' 
>>> [a[i] if i in a else 0 for i in xrange(max(a) + 1)] 
[0, 0, 7, 0, 'x'] 
1

Một phiên bản nâng cao từ câu trả lời của @Finn.

class defaultlist(list): 
    """List returning default value when accessing uninitialized index. 

    Original implementation: http://stackoverflow.com/a/8719940/315168 
    """ 

    def __init__(self, fx): 
     self._fx = fx 

    def __setitem__(self, index, value): 
     while len(self) <= index: 
      self.append(self._fx()) 
     list.__setitem__(self, index, value) 

    def __getitem__(self, index): 
     """Allows self.dlist[0] style access before value is initialized.""" 
     while len(self) <= index: 
      self.append(self._fx()) 
     return list.__getitem__(self, index) 
Các vấn đề liên quan