让我们说我们有一个迭代器:
Iterator i;
两种Java方法:
static X f(Iterator i)
static Y g(Iterator i)
它们都通过迭代器处理并产生结果,比如“sum”,“product”或其他东西。
请说出给定i
的这些调用的结果是:
x == f(i)
y == g(i)
让我们说我们有另一个班级:
class Pair<X,Y>
{
public X x;
public Y y;
}
我想写一个方法:
static Pair<X,Y> h(Iterator i)
那样:
h(i) == Pair<X,Y>(x,y);
如何在不修改或重写h
或f
的情况下撰写g
?问题是我可能无法复制迭代器(例如它可能是输入流),所以我认为f
和g
都必须在“并行”中使用迭代器”。我宁愿不把迭代器的全部内容放到列表中,也许不可能,好像我正在流式传输一个大型的源代码,我可能没有足够的内存。但是我不要求解决方案有多个线程,如果可能的话,我更愿意采用更简单的方法。
答案 0 :(得分:2)
这与你拥有的迭代器无关。你需要一个非常详细的方案,类似于* nix的tee
命令,仅适用于Java迭代器:一个包含你的初始迭代器的对象,并根据需要使用它,并且可以请求生成一个或多个“输出”迭代器。在里面,您可以使用队列来存储未消耗的元素。
如果你不想要多线程,那么从理论上讲很容易实现你必须缓存初始迭代器的整个产生。这是因为你的迭代器消耗方法都基于“拉”方法,并且在返回之前将坚持使用整个序列。
在Clojure中BTW项目 lamina 做了一些非常相似的事情,而不是Java迭代器,但是它的概念称之为“频道”。答案 1 :(得分:1)
诀窍是让stacktrace知道这两个方法中哪一个调用了iterator.next方法。
只要两个呼叫者都没有呼叫next(),就会阻止前一个呼叫。
originalIterator基于List,但使用您希望的数据结构。如您所见,stream.iterrator()只被调用一次。
public static class InterleavingIterator<E> implements Iterator<E> {
private boolean hasNext;
private E next;
private final Iterator<E> originalIterator;
private final Map<String, Integer> stepCaller = Collections.synchronizedMap(new HashMap<String, Integer>());
private final AtomicInteger curStep = new AtomicInteger(0);
public InterleavingIterator(Iterator<E> originalIterator, String caller1, String caller2) {
this.originalIterator = originalIterator;
stepCaller.put(caller1, 0);
stepCaller.put(caller2, 0);
hasNext = originalIterator.hasNext();
}
public boolean hasNext() {
return hasNext;
}
public E next() {
String caller = getCurrentCaller();
int currentStep = curStep.get();
System.out.println("caller is " + caller);
if (stepCaller.get(caller) == currentStep) {
System.out.println("Caller " + caller + " is on current step. We need to move on.");
// we should go on next step. But first check that all caller are done with this step.
while (otherCallerBehind(currentStep)) {
System.out.println("Other caller are behind. Waiting for them...");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
System.out.println("Ok, everybody is on current step. Going on.");
synchronized (curStep) {
if (currentStep == curStep.get()) {
// ok, go on.
curStep.incrementAndGet();
next = hasNext ? originalIterator.next() : null;
hasNext = originalIterator.hasNext();
System.out.println("hasNext=" + hasNext + ", next=" + next + ", currentStep=" + curStep.get());
}
}
}
E next2 = next;
stepCaller.put(caller, stepCaller.get(caller) + 1);
System.out.println("Caller " + caller + " is now at step " + stepCaller.get(caller) + ". Returning already fetch next : "
+ next);
return next2;
}
private boolean otherCallerBehind(int currentStep) {
for (Integer step : stepCaller.values()) {
if (step < currentStep) {
return true;
}
}
return false;
}
public void remove() {
throw new RuntimeException("Method remove not supported");
}
public String getCurrentCaller() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// System.out.println(stackTraceElements[3].getMethodName());
return stackTraceElements[3].getMethodName();
}
}
public static void main(String[] args) {
List<Integer> stream = Arrays.asList(1, 2, 3, 4, 5);
final InterleavingIterator<Integer> interleavingIterator = new InterleavingIterator<Integer>(stream.iterator(), "f", "g");
final AtomicInteger fres = new AtomicInteger(-1);
final AtomicInteger gres = new AtomicInteger(-1);
new Thread() {
@Override
public void run() {
fres.set(f(interleavingIterator));
};
}.start();
new Thread() {
@Override
public void run() {
gres.set(g(interleavingIterator));
};
}.start();
while (fres.get() == -1 && gres.get() == -1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(fres);
System.out.println(gres);
}
public static Integer f(Iterator<Integer> i) {
Integer sum = 0;
while (i.hasNext()) {
sum += i.next();
}
return sum;
}
public static Integer g(Iterator<Integer> i) {
Integer prod = 1;
while (i.hasNext()) {
prod *= i.next();
}
return prod;
}
答案 2 :(得分:0)
由于您可能知道要迭代的内容,因此可以获取值,将其放入新列表中,并将其迭代器传递给函数。
Pair<X,Y> getPair(Iterator i) {
ValObj value = null;
List<ValObj> artList = new LinkedList<ValObj>();
while ((value=i.next())!=null) {
artList.add(value);
}
X x = f(artList.iterator());
Y y = g(artList.iterator());
return new Pair<X,Y>(x,y);
}
现在我注意到你不想将内容存储在列表中。如果是这种情况,没有关于迭代器的更多细节,我相信它是不可能的。