Nếu tôi có một danh sách chứa [alice, bob, abigail, charlie]
và tôi muốn viết một trình lặp sao cho nó lặp qua các phần tử bắt đầu bằng 'a', tôi có thể viết một trình lặp của riêng mình không? Làm thế nào tôi có thể làm điều đó ?
Nếu tôi có một danh sách chứa [alice, bob, abigail, charlie]
và tôi muốn viết một trình lặp sao cho nó lặp qua các phần tử bắt đầu bằng 'a', tôi có thể viết một trình lặp của riêng mình không? Làm thế nào tôi có thể làm điều đó ?
Câu trả lời:
Chắc chắn rồi. Một trình lặp chỉ là một triển khai của java.util.Iterator
giao diện. Nếu bạn đang sử dụng một đối tượng có thể lặp lại hiện tại (giả sử, a LinkedList
) từ java.util
, bạn sẽ cần phải phân lớp nó và ghi đè iterator
chức năng của nó để bạn trả về đối tượng của riêng mình hoặc cung cấp một phương tiện để gói một trình lặp tiêu chuẩn trong phiên bản đặc biệt của bạn Iterator
(mà có lợi thế là được sử dụng rộng rãi hơn), v.v.
Iterator
trường hợp đặc biệt của bạn ..." (và cảm ơn). :-)
Tùy chọn có thể tái sử dụng tốt nhất là triển khai giao diện Có thể lặp lại và ghi đè phương thức iterator ().
Đây là một ví dụ về một lớp ArrayList như triển khai giao diện, trong đó bạn ghi đè phương thức Iterator ().
import java.util.Iterator;
public class SOList<Type> implements Iterable<Type> {
private Type[] arrayList;
private int currentSize;
public SOList(Type[] newArray) {
this.arrayList = newArray;
this.currentSize = arrayList.length;
}
@Override
public Iterator<Type> iterator() {
Iterator<Type> it = new Iterator<Type>() {
private int currentIndex = 0;
@Override
public boolean hasNext() {
return currentIndex < currentSize && arrayList[currentIndex] != null;
}
@Override
public Type next() {
return arrayList[currentIndex++];
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
return it;
}
}
Lớp này thực hiện giao diện có thể lặp lại bằng cách sử dụng Generics . Xem xét bạn có các phần tử trong mảng, bạn sẽ có thể nhận được một phiên bản của một Iterator, ví dụ: là phiên bản cần thiết được sử dụng bởi vòng lặp "foreach".
Bạn chỉ có thể tạo một phiên bản ẩn danh của trình vòng lặp mà không cần tạo Trình lặp mở rộng và tận dụng giá trị của currentSize để xác minh nơi bạn có thể điều hướng trên mảng (giả sử bạn đã tạo một mảng có dung lượng là 10, nhưng bạn chỉ có 2 phần tử 0 và 1). Phiên bản sẽ có bộ đếm chủ sở hữu của nó về vị trí của nó và tất cả những gì bạn cần làm là chơi với hasNext (), xác minh xem giá trị hiện tại có phải là null hay không và tiếp theo (), sẽ trả về phiên bản currentIndex của bạn. Dưới đây là một ví dụ về việc sử dụng API này ...
public static void main(String[] args) {
// create an array of type Integer
Integer[] numbers = new Integer[]{1, 2, 3, 4, 5};
// create your list and hold the values.
SOList<Integer> stackOverflowList = new SOList<Integer>(numbers);
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(Integer num : stackOverflowList) {
System.out.print(num);
}
// creating an array of Strings
String[] languages = new String[]{"C", "C++", "Java", "Python", "Scala"};
// create your list and hold the values using the same list implementation.
SOList<String> languagesList = new SOList<String>(languages);
System.out.println("");
// Since our class SOList is an instance of Iterable, then we can use it on a foreach loop
for(String lang : languagesList) {
System.out.println(lang);
}
}
// will print "12345
//C
//C++
//Java
//Python
//Scala
Nếu muốn, bạn cũng có thể lặp lại nó bằng cách sử dụng thể hiện Iterator:
// navigating the iterator
while (allNumbers.hasNext()) {
Integer value = allNumbers.next();
if (allNumbers.hasNext()) {
System.out.print(value + ", ");
} else {
System.out.print(value);
}
}
// will print 1, 2, 3, 4, 5
Tài liệu foreach có tại http://download.oracle.com/javase/1,5.0/docs/guide/language/foreach.html . Bạn có thể xem cách triển khai đầy đủ hơn tại mã google thực hành cá nhân của tôi .
Bây giờ, để có được những hiệu ứng của những gì bạn cần, tôi nghĩ bạn cần phải cắm một khái niệm về bộ lọc trong Iterator ... Vì trình lặp phụ thuộc vào các giá trị tiếp theo, sẽ khó trả về true trên hasNext (), và sau đó lọc triển khai next () với giá trị không bắt đầu bằng char "a" chẳng hạn. Tôi nghĩ bạn cần phải thử với một Interator phụ dựa trên một danh sách đã lọc với các giá trị với bộ lọc đã cho.
for instance
, đó có phải là một cách chơi chữ?
Ví dụ tốt cho Iterable để tính giai thừa
FactorialIterable fi = new FactorialIterable(10);
Iterator<Integer> iterator = fi.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
Mã ngắn cho Java 1.8
new FactorialIterable(5).forEach(System.out::println);
Lớp có thể lặp lại tùy chỉnh
public class FactorialIterable implements Iterable<Integer> {
private final FactorialIterator factorialIterator;
public FactorialIterable(Integer value) {
factorialIterator = new FactorialIterator(value);
}
@Override
public Iterator<Integer> iterator() {
return factorialIterator;
}
@Override
public void forEach(Consumer<? super Integer> action) {
Objects.requireNonNull(action);
Integer last = 0;
for (Integer t : this) {
last = t;
}
action.accept(last);
}
}
Lớp Trình lặp tùy chỉnh
public class FactorialIterator implements Iterator<Integer> {
private final Integer mNumber;
private Integer mPosition;
private Integer mFactorial;
public FactorialIterator(Integer number) {
this.mNumber = number;
this.mPosition = 1;
this.mFactorial = 1;
}
@Override
public boolean hasNext() {
return mPosition <= mNumber;
}
@Override
public Integer next() {
if (!hasNext())
return 0;
mFactorial = mFactorial * mPosition;
mPosition++;
return mFactorial;
}
}
Đây là mã hoàn chỉnh để viết một trình lặp để nó lặp qua các phần tử bắt đầu bằng 'a':
import java.util.Iterator;
public class AppDemo {
public static void main(String args[]) {
Bag<String> bag1 = new Bag<>();
bag1.add("alice");
bag1.add("bob");
bag1.add("abigail");
bag1.add("charlie");
for (Iterator<String> it1 = bag1.iterator(); it1.hasNext();) {
String s = it1.next();
if (s != null)
System.out.println(s);
}
}
}
Lớp Trình lặp tùy chỉnh
import java.util.ArrayList;
import java.util.Iterator;
public class Bag<T> {
private ArrayList<T> data;
public Bag() {
data = new ArrayList<>();
}
public void add(T e) {
data.add(e);
}
public Iterator<T> iterator() {
return new BagIterator();
}
public class BagIterator<T> implements Iterator<T> {
private int index;
private String str;
public BagIterator() {
index = 0;
}
@Override
public boolean hasNext() {
return index < data.size();
}
@Override
public T next() {
str = (String) data.get(index);
if (str.startsWith("a"))
return (T) data.get(index++);
index++;
return null;
}
}
}
Bạn có thể triển khai Iterator của riêng mình. Trình vòng lặp của bạn có thể được xây dựng để bao bọc Trình lặp lại do Danh sách trả về hoặc bạn có thể giữ một con trỏ và sử dụng phương thức get (int index) của Danh sách. Bạn chỉ cần thêm logic vào phương thức tiếp theo của Iterator VÀ phương thức hasNext để tính đến tiêu chí lọc của bạn. Bạn cũng sẽ phải quyết định xem trình lặp của mình có hỗ trợ thao tác xóa hay không.
Đây là câu trả lời đầy đủ cho câu hỏi.
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
class ListIterator implements Iterator<String>{
List<String> list;
int pos = 0;
public ListIterator(List<String> list) {
this.list = list;
}
@Override
public boolean hasNext() {
while(pos < list.size()){
if (list.get(pos).startsWith("a"))
return true;
pos++;
}
return false;
}
@Override
public String next() {
if (hasNext())
return list.get(pos++);
throw new NoSuchElementException();
}
}
public class IteratorTest {
public static void main(String[] args) {
List<String> list = Arrays.asList("alice", "bob", "abigail", "charlie");
ListIterator itr = new ListIterator(list);
while(itr.hasNext())
System.out.println(itr.next()); // prints alice, abigail
}
}
ListIterator
là trình lặp cho mảng trả về các phần tử bắt đầu bằng 'a'. NoSuchElementException
ngoại lệ hợp lệ.