合并两个文本输入文件,逐个文件的每一行。见例子

时间:2017-06-26 12:59:53

标签: java-8 stream java-stream

我试图使用java 8来解决问题,我已经使用简单的for循环解决了这个问题。但是我不知道该怎么做。 问题是:

File1 : 
1,sdfasfsf
2,sdfhfghrt
3,hdfxcgyjs

File2 : 
10,xhgdfgxgf
11,hcvcnhfjh
12,sdfgasasdfa
13,ghdhtfhdsdf

输出应该像

1,sdfasfsf
10,xhgdfgxgf
2,sdfhfghrt
11,hcvcnhfjh
3,hdfxcgyjs
12,sdfgasasdfa
13,ghdhtfhdsdf

我已经基本上工作了,

核心逻辑是:

List<String> left  = readFile(lhs);
List<String> right = readFile(rhs);
int leftSize = left.size();
int rightSize = right.size();
int size =  leftSize > rightSize? leftSize : right.size();
for (int i = 0; i < size; i++) {
    if(i < leftSize) {
        merged.add(left.get(i));
    }
    if(i < rightSize) {
        merged.add(right.get(i));
    }
}
  • MergeInputs.java
  • UnitTest
  • 输入文件位于同一个repo的src / test / resources / com / linux / test / merge / list中(只允许发布两个链接)

然而,我吹嘘我可以使用溪流轻松地做到这一点,现在我不确定是否可以这样做。

非常感谢帮助。

2 个答案:

答案 0 :(得分:3)

您可以简化操作以减少每个元素的条件:

bw.close(); 

然后,可以用流操作替换第一部分:

int leftSize = left.size(), rightSize = right.size(), min = Math.min(leftSize, rightSize);
List<String> merged = new ArrayList<>(leftSize+rightSize);
for(int i = 0; i < min; i++) {
    merged.add(left.get(i));
    merged.add(right.get(i));
}
if(leftSize!=rightSize) {
    merged.addAll(
        (leftSize<rightSize? right: left).subList(min, Math.max(leftSize, rightSize)));
}

但它并不比循环变体简单得多。由于其预先列出的列表,循环变体可能更有效。

将两个操作合并到一个流操作中会更复杂(甚至可能效率更低)。

答案 1 :(得分:1)

代码逻辑应该像这样:

int leftSize = left.size();
int rightSize = right.size();
int minSize = Math.min(leftSize,rightSize);

for (int i = 0; i < minSize; i++) {
    merged.add(left.get(i));
    merged.add(right.get(i));
}

// adding remaining elements
merged.addAll(
        minSize < leftSize ? left.subList(minSize, leftSize)
                           : right.subList(minSize, rightSize)
);

另一种选择是通过Iterator使用切换模式,例如:

toggle(left, right).forEachRemaining(merged::add);

//OR using stream instead
List<String> merged = Stream.generate(toggle(left, right)::next)
                            .limit(left.size() + right.size())
                            .collect(Collectors.toList());

toggle方法如下:

<T> Iterator<? extends T> toggle(List<T> left, List<T> right) {
    return new Iterator<T>() {
        private final int RIGHT = 1;
        private final int LEFT = 0;
        int cursor = -1;
        Iterator<T>[] pair = arrayOf(left.iterator(), right.iterator());

        @SafeVarargs
        private final Iterator<T>[] arrayOf(Iterator<T>... iterators) {
            return iterators;
        }

        @Override
        public boolean hasNext() {
            for (Iterator<T> each : pair) {
                if (each.hasNext()) {
                    return true;
                }
            }
            return false;
        }

        @Override
        public T next() {
            return pair[cursor = next(cursor)].next();
        }

        private int next(int cursor) {
            cursor=pair[LEFT].hasNext()?pair[RIGHT].hasNext()?cursor: RIGHT:LEFT;
            return (cursor + 1) % pair.length;
        }
    };
}