提问人:John Doe 提问时间:4/25/2022 最后编辑:Alexander IvanchenkoJohn Doe 更新时间:9/19/2022 访问量:805
如何实现嵌套列表迭代器
How to implement a Nested List Iterator
问:
在一次采访中,我被问到这个问题:
“如何实现自定义嵌套列表迭代器?”
方法应首先返回每个列表的第一个元素,然后返回第二个元素,依此类推。next()
输入示例:
[[1,2,3],[4,5],[6],[],[7,8,9]]
输出:
[1,4,6,7,2,5,8,3,9]
存根代码:
public class CustomListIterator implements Iterator<Integer> {
public CustomListIterator(List<List<Integer>> nestedList) {
}
@Override
public boolean hasNext() {
}
@Override
public Integer next() {
}
}
如何实施?
答:
您可以通过利用 和 的组合来实现这一点。这种方法使您可以摆脱维持任何头寸的必要性。ListIterator
Iterator
一般的想法是创建一个迭代器列表和一个将遍历这些列表的 listIterator。
方法对列表执行迭代,并检查它是否至少有一个未耗尽的迭代器。hasNext()
方法更复杂一些。首先,它将尝试将 listIterator 从最后一个元素后面的位置“重置”到列表第一个元素之前的位置。next()
然后在循环中,它将检查列表中的下一个迭代器,如果此迭代器耗尽,它将被删除。为了使此操作快速,迭代器存储在 .如果找到该元素,它将被退回。LinkedList
为了处理“空”迭代器出现在列表末尾并且 listIterator 到达最后一个位置,但列表中可能还有更多未访问的迭代器的情况,在循环的末尾放置了一个额外的检查。
在下面的实现中,为了简洁起见,我在内部使用了流和构造函数。即使你对流不是很熟悉,整体逻辑也应该很清楚,你可以很容易地用流代替它。hasNext()
public class CustomListIterator<T> implements Iterator<T> {
private List<Iterator<T>> iterators;
private ListIterator<Iterator<T>> listIterator;
public CustomListIterator(List<List<T>> nestedList) {
this.iterators = nestedList.stream()
.map(List::iterator)
.collect(Collectors.toCollection(LinkedList::new));
this.listIterator = iterators.listIterator();
}
@Override
public boolean hasNext() {
return iterators.stream().anyMatch(Iterator::hasNext);
}
@Override
public T next() {
if (!iterators.isEmpty() && !listIterator.hasNext()) tryReset();
while (!iterators.isEmpty() && listIterator.hasNext()) {
Iterator<T> current = listIterator.next();
if (!current.hasNext()) {
listIterator.remove(); // removing exhausted iterator
} else {
return current.next();
}
if (!listIterator.hasNext()) tryReset();
}
throw new IllegalStateException();
}
private void tryReset() {
while (listIterator.hasPrevious()) {
listIterator.previous();
}
}
}
main()
-演示
public static void main(String[] args) {
List<List<Integer>> numbers =
List.of(List.of(1, 4, 6, 7),
List.of(),
List.of(2, 5),
List.of(3));
CustomListIterator<Integer> nestedIterator = new CustomListIterator<>(numbers);
while (nestedIterator.hasNext()) {
System.out.print(nestedIterator.next() + "\t");
}
}
输出
1 2 3 4 5 6 7
为了实现迭代器,我们需要一个光标来跟踪我们当前所在的元素。根据底层数据结构,所述光标可以是索引或指针,它将用于从一个元素前进到另一个元素。这是在 next() 方法中完成的,该方法返回当前元素,光标前进到下一个元素。
因为在您的问题中,您要求为泛型列表(不是专门针对 ArrayList 或 LinkedList)的自定义迭代器;我决定使用 int 索引作为光标,以便指向两种数据结构的元素。
为了回答您的问题,我将您的列表列表描绘成一个具有不同长度行的矩阵,我们首先遍历当前列的行(外部列表光标),然后移动到下一列(内部列表或子列表光标)。
class CustomListIteratorVert implements Iterator<Integer> {
private List<List<Integer>> nestedList;
private int listCur, subListCur;
//value to understand when the iteration has completed since the "column" cursor has reached its end
private int maxSublistSize;
public CustomListIteratorVert(List<List<Integer>> nestedList) {
this.nestedList = nestedList;
this.listCur = 0;
this.subListCur = 0;
//Identifying the greates size among the sublists
this.maxSublistSize = nestedList.stream().map(list -> list.size()).max(Integer::compareTo).orElse(0);
}
@Override
public boolean hasNext() {
//If the sublist cursor hasn't exceeded the last "column" then there are further elements to iterate (worst case scenario: only the current element)
return subListCur < maxSublistSize;
}
@Override
public Integer next() {
//If the last column has been exceeded (no further elements to iterate) then no value is returned
if (subListCur == maxSublistSize) {
return null;
}
//Saving the current value to return
Integer value = nestedList.get(listCur).get(subListCur);
//Incrementing the outer list cursor to point to the next "row" (matrix visualization)
if (listCur < nestedList.size() - 1) {
listCur++;
} else {
//Incrementing the sublist cursors to point to the next column and resetting the "row" index (matrix visualization)
subListCur++;
listCur = 0;
}
// In case there are still elements left and the current cursors do not point to an existing element (sublist cursor greater than the sublist's size)
// then these "empty spots" are skipped as long as the last column hasn't been exceeded or the next element hasn't been met
while (subListCur < maxSublistSize && subListCur >= nestedList.get(listCur).size()) {
if (listCur < nestedList.size() - 1) {
listCur++;
} else {
subListCur++;
listCur = 0;
}
}
return value;
}
}
public class Main {
public static void main(String[] args) {
//Added extra empty lists to create more "empty sposts"
List<List<Integer>> nestedList = new ArrayList<>(List.of(List.of(1, 2, 3), List.of(4, 5), List.of(6), List.of(), List.of(7, 8, 9), List.of(), List.of()));
System.out.println("------------ Iterator ------------");
CustomListIteratorVert custIt = new CustomListIteratorVert(nestedList);
while (custIt.hasNext()) {
System.out.println(custIt.next());
}
System.out.println("\n\n------------ Flattened List foreach loop ------------");
List<Integer> listFlattenedFor = new ArrayList<>();
for (List<Integer> sublist : nestedList) {
listFlattenedFor.addAll(sublist);
}
listFlattenedFor.forEach(i -> System.out.println(i));
System.out.println("\n\n------------ Flattened List Stream ------------");
List<Integer> listFlattenedStream = new ArrayList<>();
nestedList.stream().forEach(list -> listFlattenedStream.addAll(list));
listFlattenedFor.forEach(i -> System.out.println(i));
}
}
评论