2012-03-15 21 views
61

Có cách nhanh chóng "tính toán" để nhận số đếm của trình lặp không?Cách tốt nhất để có được số lượng/chiều dài/kích thước của một trình lặp là gì?

int i = 0; 
for (; some_iterator.hasNext() ; ++i) some_iterator.next(); 

... có vẻ như lãng phí các chu kỳ CPU.

+2

Trình lặp không nhất thiết phải tương ứng với một số "đếm" ... –

+0

Bộ lặp là những gì chúng đang có; để lặp lại đối tượng tiếp theo của một bộ sưu tập (nó có thể là bất cứ thứ gì như tập hợp, mảng, v.v.) Tại sao chúng cần phải nói kích thước khi chúng không quan tâm đến những gì chúng đang cố lặp lại? 'để cung cấp phương thức độc lập để truy cập, trong đó người dùng không cần biết liệu triển khai cơ bản có là một dạng mảng hoặc danh sách được liên kết hay không và cho phép người dùng đi qua bộ sưu tập mà không lập chỉ mục rõ ràng.' http://penguin.ewu.edu/~trolfe/LinkedSort/Iterator.html – ecle

Trả lời

52

Nếu bạn vừa nhận được iterator thì đó là những gì bạn sẽ phải làm - nó không biết bao nhiêu mục nó đã trái sang lặp lại, vì vậy bạn không thể truy vấn nó cho kết quả đó.

Tuy nhiên, nhiều trình vòng lặp đến từ các bộ sưu tập mà bạn thường có thể truy vấn kích thước của chúng. Và nếu đó là lớp do người dùng tạo, bạn sẽ nhận được trình vòng lặp cho, bạn có thể xem xét để cung cấp một phương thức size() trên lớp đó.

Tóm lại, trong trường hợp bạn chỉ có trình lặp thì không có cách nào tốt hơn, nhưng thường xuyên hơn bạn không có quyền truy cập vào bộ sưu tập hoặc đối tượng bên dưới mà bạn có thể nhận kích thước trực tiếp .

4

Không có cách nào hiệu quả hơn, nếu tất cả những gì bạn có là trình lặp. Và nếu iterator chỉ có thể được sử dụng một lần, sau đó nhận được số lượng trước khi bạn nhận được nội dung của iterator là ... có vấn đề.

Giải pháp là thay đổi ứng dụng của bạn để ứng dụng không cần tính hoặc để có được số đếm bằng một số phương tiện khác. (Ví dụ, thông qua một Collection hơn Iterator ...)

7

Mã của bạn sẽ cung cấp cho bạn một ngoại lệ khi bạn đến cuối trình lặp. Bạn có thể làm:

int i = 0; 
while(iterator.hasNext()) { 
    i++; 
    iterator.next(); 
} 

Nếu bạn có quyền truy cập vào bộ sưu tập cơ bản, bạn sẽ có thể gọi coll.size() ...

EDIT OK bạn đã sửa đổi ...

-3

iterator đối tượng chứa cùng một số yếu tố mà bộ sưu tập của bạn chứa.

List<E> a =...; 
Iterator<E> i = a.iterator(); 
int size = a.size();//Because iterators size is equal to list a's size. 

Nhưng thay vì nhận được kích thước của iterator và lặp lại thông qua chỉ số từ 0 đến kích thước đó, nó là tốt hơn để lặp qua các phương pháp tiếp theo() của iterator.

+0

Nếu chúng ta không có 'a', nhưng chỉ có' ​​i' thì sao? – Tvde1

5

Nếu tất cả những gì bạn có là trình lặp, thì không, không có cách nào "tốt hơn". Nếu trình vòng lặp đến từ một bộ sưu tập, bạn có thể làm như vậy cho kích thước.

Hãy ghi nhớ rằng Iterator chỉ là một giao diện để vượt qua giá trị khác biệt, bạn sẽ rất tốt có mã như thế này

new Iterator<Long>() { 
     final Random r = new Random(); 
     @Override 
     public boolean hasNext() { 
      return true; 
     } 

     @Override 
     public Long next() { 
      return r.nextLong(); 
     } 

     @Override 
     public void remove() { 
      throw new IllegalArgumentException("Not implemented"); 
     } 
    }; 

hoặc

new Iterator<BigInteger>() { 
     BigInteger next = BigInteger.ZERO; 

     @Override 
     public boolean hasNext() { 
      return true; 
     } 

     @Override 
     public BigInteger next() { 
      BigInteger current = next; 
      next = next.add(BigInteger.ONE); 
      return current; 
     } 

     @Override 
     public void remove() { 
      throw new IllegalArgumentException("Not implemented"); 
     } 
    }; 
71

Sử dụng Guava library:

int size = Iterators.size(iterator); 

Nội bộ nó chỉ lặp qua tất cả các yếu tố để nó chỉ thuận tiện.

4

Một tùy chọn khác là chuyển đổi Iterable thành List.

int count = Lists.newArrayList(some_iterator).size(); 
+1

Bao nhiêu nó sẽ hiệu quả ??? – LoveToCode

+2

@LoveToCode Ít hiệu quả hơn ví dụ về câu hỏi gốc – Winter

+2

Chắc chắn, việc tạo một đối tượng mới với tất cả các phần tử chậm hơn so với chỉ lặp lại và loại bỏ. IMHO, giải pháp này là một lớp lót giúp cải thiện khả năng đọc mã. Tôi sử dụng nó rất nhiều cho các bộ sưu tập với vài yếu tố (lên đến 1000) hoặc khi tốc độ không phải là một vấn đề. – tashuhka

2

Bạn sẽ luôn phải lặp lại. Tuy nhiên, bạn có thể sử dụng Java 8, 9 để làm đếm không lặp explicitely:

Iterable<Integer> newIterable =() -> iter; 
long count = StreamSupport.stream(newIterable.spliterator(), false).count(); 

Dưới đây là một thử nghiệm:

public static void main(String[] args) throws IOException { 
    Iterator<Integer> iter = Arrays.asList(1, 2, 3, 4, 5).iterator(); 
    Iterable<Integer> newIterable =() -> iter; 
    long count = StreamSupport.stream(newIterable.spliterator(), false).count(); 
    System.out.println(count); 
} 

in này:

5 

Thú vị đủ, bạn có thể parallelize hoạt động đếm tại đây bằng cách thay đổi cờ parallel trên cuộc gọi này:

long count = StreamSupport.stream(newIterable.spliterator(), *true*).count(); 
Các vấn đề liên quan