2012-06-29 50 views
6

Tôi làm cách nào để có thể tương đương với Python pdtolist từ Pop-11?Danh sách động tự động mở rộng

Giả sử tôi có máy phát điện được gọi là g trả về (số nguyên) mỗi lần một số nguyên. Tôi muốn xây dựng danh sách a tự động phát triển khi tôi yêu cầu các giá trị vượt quá đầu hiện tại của danh sách. Ví dụ:

print a # => [ 0, 1, 2, g] 
print a[0] # => 0 
print a[1] # => 1 
print a[2] # => 2 
# (obvious enough up to here) 

print a[6] # => 6 
print a # => [ 0, 1, 2, 3, 4, 5, 6, g] 
# list has automatically expanded 

a = a[4:] # discard some previous values 
print a # => [ 4, 5, 6, g] 
print a[0] # => 4 

ngữ - dự đoán một sự hiểu lầm có khả năng: một danh sách là một "mảng động" nhưng đó không phải những gì tôi có ý nghĩa; Tôi muốn một "danh sách động" theo nghĩa trừu tượng hơn.

Để giải thích động lực tốt hơn, giả sử bạn có 999999999 mục cần xử lý. Cố gắng để phù hợp với tất cả những người vào bộ nhớ (trong một danh sách bình thường) tất cả cùng một lúc sẽ là một thách thức. Một máy phát điện giải quyết một phần của vấn đề bằng cách trình bày chúng cùng một lúc; mỗi cái được tạo theo yêu cầu hoặc đọc riêng từ đĩa. Nhưng giả sử trong quá trình xử lý bạn muốn tham khảo một số giá trị gần đây, không chỉ là giá trị hiện tại? Bạn có thể nhớ mười (mười) giá trị cuối cùng trong một danh sách riêng biệt. Nhưng một danh sách động là tốt hơn, vì nó ghi nhớ chúng tự động.

+0

Ghi đè phương thức '__getitem__' của danh sách để bắt' IndexError'. –

+0

Vì vậy, bạn có danh sách 'L' và thực hiện' L [999999999] '- danh sách sẽ trở thành chiều dài đó? –

+0

Vâng, về nguyên tắc. Caveat programmor! –

Trả lời

2

Rất cám ơn tất cả những người đã đóng góp ý tưởng! Đây là những gì tôi đã tập hợp lại từ tất cả các câu trả lời. Điều này giữ lại hầu hết các chức năng từ lớp danh sách thông thường, bổ sung thêm các hành vi cần thiết để đáp ứng các yêu cầu bổ sung.

class DynamicList(list): 
    def __init__(self, gen): 
     self.gen = gen 

    def __getitem__(self, index): 
     while index >= len(self): 
      self.append(next(self.gen)) 
     return super(DynamicList, self).__getitem__(index) 

    def __getslice__(self, start, stop): 
     # treat request for "last" item as "most recently fetched" 
     if stop == 2147483647: stop = len(self) 
     while stop > len(self): 
      self.append(next(self.gen)) 
     return super(DynamicList, self).__getslice__(start, stop) 

    def __iter__(self): 
     return self 

    def next(self): 
     n = next(self.gen) 
     self.append(n) 
     return n 

a = DynamicList(iter(xrange(10))) 

Giá trị được tạo trước đây có thể được truy cập riêng lẻ dưới dạng mục hoặc lát. Lịch sử được ghi mở rộng khi cần thiết nếu (các) mục được yêu cầu vượt quá đầu hiện tại của danh sách. Toàn bộ lịch sử được ghi có thể được truy cập cùng một lúc, sử dụng print a hoặc được gán cho một danh sách thông thường bằng cách sử dụng b = a[:]. Bạn có thể xóa một phần lịch sử đã ghi bằng cách sử dụng del a[0:4]. Bạn có thể lặp qua toàn bộ danh sách bằng cách sử dụng for, xóa khi bạn đi hoặc bất cứ khi nào nó phù hợp. Nếu bạn đạt đến cuối giá trị được tạo, StopIteration sẽ được tăng lên.

Một số lúng túng vẫn còn. Các nhiệm vụ như a = a[0:4] cắt ngắn thành công lịch sử, nhưng danh sách kết quả không còn tự động mở rộng. Thay vào đó hãy sử dụng del a[0:4] để giữ lại các thuộc tính tăng trưởng tự động. Ngoài ra, tôi không hoàn toàn hài lòng khi phải nhận ra một giá trị ma thuật, 2147483647, đại diện cho mục gần đây nhất.

2

Điều này có thể giúp bạn bắt đầu:

class DynamicList(list): 
    def __init__(self, gen): 
     self._gen = gen 

    def __getitem__(self, index): 
     while index >= len(self): 
      self.append(next(self._gen)) 
     return super(DynamicList, self).__getitem__(index) 

Bạn sẽ cần phải thêm một số xử lý đặc biệt cho lát (hiện tại, họ chỉ trả về một danh sách bình thường, vì vậy bạn mất hành vi năng động). Ngoài ra, nếu bạn muốn bản thân trình tạo là một mục danh sách, điều đó sẽ thêm một chút phức tạp.

+0

Đây không phải là danh sách con; '__init__' không tương thích và không hỗ trợ' __len__' hoặc '__setitem__' ... – agf

+0

@agf: Vấn đề' __init__' là một điểm hợp lệ, nhưng tại sao nó không hỗ trợ '__len__' hoặc' __setitem__'? – voithos

+0

Độ dài của nó không xác định bởi vì độ dài của máy phát không xác định và chỉ phản ánh các mục từ trình tạo, vì vậy bạn không thể chỉ định cho máy phát. – agf

1

Chỉ cần trả lời một câu hỏi tương tự khác và quyết định cập nhật câu trả lời của tôi cho bạn tên này?

class dynamic_list(list): 
    def __init__(self,num_gen): 
     self._num_gen = num_gen 
    def __getitem__(self,index): 
     if isinstance(index, int): 
      self.expandfor(index) 
      return super(dynamic_list,self).__getitem__(index) 

     elif isinstance(index, slice): 
      if index.stop<index.start: 
       return super(dynamic_list,self).__getitem__(index) 
      else: 
       self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start) 
      return super(dynamic_list,self).__getitem__(index) 

    def __setitem__(self,index,value): 
     if isinstance(index, int): 
      self.expandfor(index) 
      return super(dynamic_list,self).__setitem__(index,value) 

     elif isinstance(index, slice): 
      if index.stop<index.start: 
       return super(dynamic_list,self).__setitem__(index,value) 
      else: 
       self.expandfor(index.stop if abs(index.stop)>abs(index.start) else index.start) 
      return super(dynamic_list,self).__setitem__(index,value) 

    def expandfor(self,index): 
      rng = [] 
      if abs(index)>len(self)-1: 
       if index<0: 
        rng = xrange(abs(index)-len(self)) 
       else: 
        rng = xrange(abs(index)-len(self)+1) 
      for i in rng: 
       self.append(self._num_gen.next()) 
Các vấn đề liên quan