2

I have two arraylists

    ArrayList<File> filesImage= new ArrayList<File>();
    ArrayList<File> filesBox= new ArrayList<File>();

I want to merge into third arraylist like this

    ArrayList<File[]> combinedFiles=new ArrayList<File[]>();

How can I do this? Output should be like:

   [[ first object of filesImage, first object of filesBox],[second Object],[]]
user3125261
  • 85
  • 2
  • 10
  • 1
    @ΦXocę웃Пepeúpaツ No that add's in linear way. Not as a individual array. – Suresh Atta Apr 25 '17 at 10:36
  • What have you tried so far? @ΦXocę웃Пepeúpaツ addAll would add all entries from one collection to the other, not "zip" them into pairs in arrays. – G_H Apr 25 '17 at 10:36
  • How about iterating over the lists simultaneously and building and adding the element array for each iteration? Or yet better, why don't you build a small object that contains both file references to make it less error-prone and easier to understand? – Thomas Apr 25 '17 at 10:40
  • 3
    As an aside, I'd probably use a `Map` for this instead, it expresses the structure of your data more accurately. But the basic solution is the same in both cases: iterate across the two lists in parallel and pick one element from each in every step. – biziclop Apr 25 '17 at 10:40
  • @biziclop i tried with map its working but not the way i want it. Its giving a key-value pairs. I want to store path of 2 files in array of a arraylist – user3125261 Apr 25 '17 at 10:46
  • Fair enough, from your example it seemed that key-value is what you're after. – biziclop Apr 25 '17 at 10:47

6 Answers6

5

Given that the two arrays are of equal length that you wish to combine, i'd personally do something like this.

List<File[]> combinedFiles= new ArrayList<File[]>();

for(int i = 0; i < filesBox.size(); i++){
    combinedFiles.add(new File[] {filesImage.get(i), filesBox.get(i)});
}

Apologies if my methods are incorrect, its been a while since i've programmed in java.

Ryan Turnbull
  • 3,766
  • 1
  • 25
  • 35
5

First, I'd create a class that holds the file references, e.g. like this:

class FileElement {
  File image;
  File box;
}

Then I'd create a list of those instead of arrays:

List<FileElement> combinedFiles = ...;

Then I'd iterate over both lists simultaneously:

Iterator<File> imgItr = filesImages.iterator();
Iterator<File> boxItr = filesBox.iterator();

//This assumes it's ok if both lists have different sizes. 
//If it isn't you could try && instead, i.e. stop once you'd miss an image or a box
while( imgItr.hasNext() || boxItr.hasNext() ) {
   FileElement e = ...;

   if( imgItr.hasNext() ) { 
     e.image = imgItr.next();
   }

   if( boxItr.hasNext() ) { 
     e.box= boxItr.next();
   }

   combinedFiles.add( e );
}
Thomas
  • 87,414
  • 12
  • 119
  • 157
  • Encapsulating things in a class is useful if additional functionality is added to it, otherwise a 2-element array seems just fine. No need to invent more classes unless necessary. I wish Java had a Pair class... – G_H Apr 25 '17 at 10:53
  • 1
    @G_H there are reasons why there is no pair class and one is that in most cases it's better give provide names for the elements inside a pair (as an example they mention 2d points which are not just 2 `int` elements but rather provide names like `x` and `y`). Using a specific class helps making the code easier to read since if in the future you read `combinedFiles.get(0)[0]` you'll not know what that file is meant to be, but if you read `combinedFiles.get(0).image` you know that it's meant to be an image file. – Thomas Apr 25 '17 at 11:03
  • Good point, it's likely the ArrayList with arrays is gonna be passed onto some other context rather than used locally, or it wouldn't really be necessary to begin with. – G_H Apr 25 '17 at 11:20
2

Assuming that the two lists are of equal length, here is a solution using Java8 streams and zip().

import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;


public class Demo {

    public static void main( String[] args ) {
        List<String> filesImage = Arrays.asList("a","b","c");
        List<String> filesBox   = Arrays.asList("1","2", "3");

        List<String[]> result = zip(filesImage.stream(), filesBox.stream(), (a,b) -> new String[] {a,b}).collect( Collectors.toList() );

        for ( String[] e : result ) {
            System.out.println( Arrays.asList(e) );
        }
    }

    public static <A, B, C> Stream<C> zip(Stream<A> streamA, Stream<B> streamB, BiFunction<A, B, C> zipper) {
        final Iterator<A> iteratorA = streamA.iterator();
        final Iterator<B> iteratorB = streamB.iterator();
        final Iterator<C> iteratorC = new Iterator<C>() {
            @Override
            public boolean hasNext() {
                return iteratorA.hasNext() && iteratorB.hasNext();
            }

            @Override
            public C next() {
                return zipper.apply(iteratorA.next(), iteratorB.next());
            }
        };
        final boolean parallel = streamA.isParallel() || streamB.isParallel();
        return iteratorToFiniteStream(iteratorC, parallel);
    }

    public static <T> Stream<T> iteratorToFiniteStream( Iterator<T> iterator, boolean parallel) {
        final Iterable<T> iterable = () -> iterator;
        return StreamSupport.stream(iterable.spliterator(), parallel);
    }
}

I borrowed the implementation of zip from Karol Krol here. Zip is the name from the functional world for this pattern of combining two lists in this manner. Also note that while Demo uses String's instead of File, the concept remains exactly the same.

Community
  • 1
  • 1
Chris K
  • 11,622
  • 1
  • 36
  • 49
  • Having a generic zip operation is certainly nice (and I wonder why it's not available in Java SE's API) but I think this might be a bit overkill for OP's use case, and possibly over their head given the question asked. – G_H Apr 25 '17 at 10:50
  • @G_H it is useful for documenting the functional approach for others who come across the question – Chris K Apr 25 '17 at 10:52
  • 1
    That is true. My first thought was "oh, a zip" and was a bit surprised Java doesn't have it out-of-the-box. Seems a fairly fundamental FP operation. – G_H Apr 25 '17 at 10:54
1

Normally I wouldn't answer a question where OP doesn't show what they've tried, but since I'm seeing a flood of incorrect answers and interpretations...

List<File> filesImage= new ArrayList<File>();
List<File> filesBox= new ArrayList<File>();
List<File[]> combinedFiles=new ArrayList<File[]>();
for (int i = 0; i < filesImage.size(); ++i) {
    File[] temp = new File[2];
    temp[0] = filesImage.get(i);
    temp[1] = filesBox.get(i);
    combinedFiles.add(temp);
}

Something like this is known as "zipping" in functional programming, by the way. I'd suggest a solution with Java 8 lambdas, but there doesn't seem to be a zip function in Java SE and the above is quite simple.

G_H
  • 11,739
  • 3
  • 38
  • 82
0

Should work similar to this pseudo code

List<File[]> merge = new ArrayList<>();

for(int i=0;i<filesImage.legth&&i<filesBox.length;i++{
    merge.add(new File[]{i<filesImage.legth?filesImage[i]:null,i<filesBox.legth?filesBox[i]});
}
fsch
  • 201
  • 1
  • 5
  • 17
0

You can use function toArray of List to make array.

ArrayList<File> filesImage= new ArrayList<File>();
    ArrayList<File> filesBox= new ArrayList<File>();
 ArrayList<File[]> combinedFiles=new ArrayList<File[]>();
//add content to 2 lists here
File[] arrayFiles;

//add array image
arrayFiles = new File[filesImage.size()];
arrayFiles = filesImage.toArray(arrayFiles);
combinedFiles.add(arrayFiles);
//add array box
arrayFiles = new File[filesBox.size()];
arrayFiles = filesBox.toArray(arrayFiles);
combinedFiles.add(arrayFiles);

System.out.println(combinedFiles);
Don
  • 61
  • 2