2017-06-26 1 views
4

Ich habe versucht, ein Problem mit Java 8 zu lösen, das ich bereits mit einer einfachen for-Schleife gelöst habe. Ich habe jedoch keine Ahnung, wie ich das machen soll. Das Problem ist:Zwei Texteingabedateien zusammenführen, jede Zeile der Dateien nacheinander. Siehe Beispiel

File1 : 
1,sdfasfsf 
2,sdfhfghrt 
3,hdfxcgyjs 

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

Ausgabe wie

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

sein sollte ich dies bereits haben im Grunde arbeiten,

Die Kernlogik ist:

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
  • Eingabedateien sind in src/test/resources/com/linux/test/merge/Liste der gleichen Repo (nur zwei Links schreiben erlaubt)

jedoch prahlte ich, ich könnte mach das einfach mit Streams und jetzt bin ich mir nicht sicher, ob das überhaupt möglich ist.

Hilfe wird sehr geschätzt.

+0

Nicht als Antwort, da es keine Streams verwendet, aber dies ist einfach und weniger fehleranfällig mit Apache Commons Iterator-Dienstprogramme: 'Liste merged = IteratorUtils.toList (IteratorUtils.zipingIterator (left.iterator(), right.iterator())); ' –

Antwort

3

Sie können Ihren Betrieb vereinfachen, um weniger Bedingungen zu haben als pro Element:

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))); 
} 

Dann Sie kann den ersten Teil durch einen Strom Betrieb ersetzen:

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

List<String> merged=IntStream.range(0, min) 
     .mapToObj(i -> Stream.of(left.get(i), right.get(i))) 
     .flatMap(Function.identity()) 
     .collect(Collectors.toCollection(ArrayList::new)); 
if(leftSize!=rightSize) { 
    merged.addAll(
     (leftSize<rightSize? right: left).subList(min, Math.max(leftSize, rightSize))); 
} 

Aber es ist nicht wirklich einfacher als die Loop-Variante. Die Schleifenvariante kann aufgrund ihrer vordefinierten Liste sogar noch effizienter sein.

Die Integration beider Operationen in einen Stream-Vorgang wäre noch komplizierter (und wahrscheinlich sogar weniger effizient).

+0

Danke, Klingt gut. Ich werde in die Function.identity() und Flatmap mehr schauen :) Schätzen Sie die Hilfe – comdotlinux

1

sollte die Code-Logik wie dies auch sein:

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) 
); 

Eine weitere Option Toggle-Modus durch Iterator verwendet, zum Beispiel:

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()); 

die toggle wie unten Methode:

<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; 
     } 
    }; 
} 
Verwandte Themen