【问题标题】:Implementation for Iterator<List<String>> doesn't work correctlyIterator<List<String>> 的实现无法正常工作
【发布时间】:2018-02-05 16:41:01
【问题描述】:

我必须为 Iterator 接口编写一个实现。

它的构造函数应该如下所示:

public BlockIterator(Iterator<List<String>> iterator, String regex) {

长话短说,这个实现应该解析巨大的文件,因此不能将它保存到内存中(比如存储和处理到数组或集合),一切都应该“即时”操作。

另外,next() 实现应该将子列表从第一次出现的模式返回到下一个。但是,不应包含下一个。

还有一点需要注意,hasNext() 应该是幂等的。即使经过 20 次调用,结果也应该相同。

这是我的测试解决方案:

import com.google.common.collect.Lists;
import org.junit.Test;

import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

class BlockIterator implements Iterator<List<String>> {

    private final Iterator<List<String>> iterator;
    private final Pattern pattern;

    public BlockIterator(Iterator<List<String>> iterator, String regex) {
        this.iterator = iterator;
        this.pattern = Pattern.compile(regex);
    }

    @Override
    public boolean hasNext() {
        while (iterator.hasNext()) {
            List<String> line = iterator.next();
            for (String word : line) {
                Matcher matcher = pattern.matcher(word);
                if (matcher.find()) {
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public List<String> next() {
        String matchWord = null;
        List<String> result = Lists.newArrayList();

        while (iterator.hasNext()) {
            List<String> line = iterator.next();
            for (String word : line) {
                Matcher matcher = pattern.matcher(word);
                if (matcher.find()) {
                    if (null != matchWord) {
                        return result;
                    } else {
                        matchWord = word;
                    }
                }
                if (null != matchWord) {
                    result.add(word);
                }
            }
        }
        return result;
    }
}

public class BlockIteratorTest {

    public static final List<List<String>> lines = Lists.newArrayList(
            Lists.newArrayList("123"),
            Lists.newArrayList("- test -"),
            Lists.newArrayList("start"),
            Lists.newArrayList("end"),
            Lists.newArrayList("test123"));

    @Test
    public void testNext() throws Exception {
        List<String> expectedFirstNext = Lists.newArrayList("- test -", "start", "end");
        List<String> expectedSecondNext = Lists.newArrayList("test123");

        BlockIterator blockIterator = new BlockIterator(lines.iterator(), "test");

        List<String> actualFirstNext = blockIterator.next();
        assertEquals(expectedFirstNext, actualFirstNext);

        List<String> actualSecondNext = blockIterator.next();
        assertEquals(expectedSecondNext, actualSecondNext);
    }

    @Test
    public void testHasNext() throws Exception {
        BlockIterator blockIterator = new BlockIterator(lines.iterator(), "test");

        for (int i = 0; i < 20; i++) {
            assertTrue(blockIterator.hasNext());
        }
    }
}

几乎没有失败:

  • hasNext() 不是幂等的
  • 在第二次 next() 调用后,我们应该只返回匹配子列表(因为不再有文本)。

在这种情况下我找不到有效的解决方案。

有什么建议吗?

【问题讨论】:

  • 调用iterator.hasNext() 后,您将更改iterator 的状态,并且无法在hashNextnext 方法中重复使用它。也许您需要使用 Iterable&lt; List&lt;String&gt; &gt; 并在您的 hasNextnext 调用中创建一个新的迭代器。
  • @tsolakp 我无法更改实施条件。不知何故必须使用现有的选项。

标签: java unit-testing iterator implementation


【解决方案1】:

试过玩这个,不确定这是否是你的意思,但它通过了你的测试,所以......它是什么!我不明白你的第二次失败,我不确定当内部列表超过 1 个单词时你想要发生什么,但无论如何都要试试这个:

class IteratorTesting implements Iterator<List<String>> {

    private final Iterator<List<String>> iterator;
    private final Pattern pattern;

    private boolean hasNext = false;
    private List<String> next = null;
    private String startNext = null;

    public IteratorTesting(Iterator<List<String>> iterator, String regex) {
        this.iterator = iterator;
        this.pattern = Pattern.compile(regex);

        hasNext = checkNext();
    }

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

    private boolean checkNext() {
        String matchWord = null;
        List<String> result = new ArrayList<>();
        if(startNext != null)
            result.add(startNext);

        while(iterator.hasNext()) {
            List<String> line = iterator.next();
            for(String word : line) {
                Matcher matcher = pattern.matcher(word);
                if(matcher.find()) {
                    if(null != matchWord || startNext != null) {
                        next = result;
                        startNext = word;
                        return true;
                    } else {
                        matchWord = word;
                    }
                }
                if(null != matchWord || startNext != null) {
                    result.add(word);
                }
            }
        }
        next = result;
        startNext = null;
        return !next.isEmpty();
    }

    @Override
    public List<String> next() {
        List<String> current = next;
        hasNext = checkNext();
        return current;
    }
}

我知道这是糟糕的代码,即使现在我也看到了可以立即重构的东西 (if(null != matchWord || startNext != null) {...),不要恨我。

【讨论】:

    【解决方案2】:

    您可以将匹配的列表存储在字段中,将其与hasNext中的null进行比较,并在next中返回值

    【讨论】:

    • list with match 到底是什么意思?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多