Home > Back-end >  How to Merge Three Arrays by grouping Elements under the same Index together
How to Merge Three Arrays by grouping Elements under the same Index together

Time:09-18

I have three arrays like the below:

int a[] = {1,2,3,4};
int b[] = {5,6,7,8};
int c[] = {9,10,11,12};

I want to merge the above arrays by taking the first element from each array, then the second, etc. to get the below result:

int d[] = {1,5,9,2,6,10,3,7,11,4,8,12};

I have tried the following code, but as can be observed from the output it concatenates the data from each of the array rather than grouping elements under the same index together. How can I fix that?

My code:

public class MergeTwoArrays2 {

    public static void main(String[] args) {
        int a[] = {1,2,3,4};
        int b[] = {5,6,7,8};
        int c[] = {9,10,11,12};
  
        int a1 = a.length;
        int b1 = b.length;
        int c1 = c.length;
  
        int d1 = a1   b1  c1;
        
        int[] d = new int[d1];

        for (int i = 0; i < a1; i = i   1) {
            d[i] = a[i];
        }
        
        for (int i = 0; i < b1; i = i   1) {
            d[a1   i] = b[i];
        }

        for (int i = 0; i < c1; i = i   1) {
            d[a1   b1   i] = c[i];
        }

        for (int i = 0; i < d1; i = i   1) {
            System.out.println(d[i]);
        }
    }
} 

Output:

[1,2,3,4,5,6,7,8,9,10,11,12]

Expected Output:

[1,5,9,2,6,10,3,7,11,4,8,12]

CodePudding user response:

So you want to take the first element from all three arrays a, b, c, then the second one, and so on.

For that, you need a different strategy of populating the array d.

You can iterate over all your arrays simultaneously checking if the next element exists in a particular array, and if it's the case assigning it to the current position in the resulting array.

int[] d = new int[d1];
    
for (int i = 0, j = 0; i < Math.max(Math.max(a1, b1), c1);i  ) {
    if (i < a1)  d[j  ] = a[i];
    if (i < b1)  d[j  ] = b[i];
    if (i < c1)  d[j  ] = c[i];
}
    
System.out.println(Arrays.toString(d));

Output:

[1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12]

In the case when all the given arrays a, b, c are of the same length, you can get rid of the if-statements:

for (int i = 0, j = 0; i < a1; i  ) {
    d[j  ] = a[i];
    d[j  ] = b[i];
    d[j  ] = c[i];
}

Generalizing the problem

Your problem can be generalized to merging an arbitrary number of integer arrays having the same length.

That would allow eliminating duplicated statements and hard-coded names.

/**
 * Merges arbitrary number of arrays of the same length
 */
public static int[] joinAll(int[]... arrays) {
    if (arrays.length == 0) return new int[0];

    int[] result = new int[arrays.length * arrays[0].length];

    for (int i = 0, j = 0; i < arrays[0].length; i  ) {
        for (int[] arr: arrays) {
            result[j  ] = arr[i];
        }
    }
    return result;
}
System.out.println(Arrays.toString(joinAll(a, b, c)));

Output:

[1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12]

Stream-based solution

In case if you fill comfortable with Stream IPA you represent the logic from generalized method shown above using a single statement:

/**
 * Merges arbitrary number of arrays of the same length
 */
public static int[] joinAll(int[]... arrays) {
    if (arrays.length == 0) return new int[0];
    
    return IntStream.range(0, arrays[0].length)
        .flatMap(i -> Arrays.stream(arrays).mapToInt(arr -> arr[i]))
        .toArray();
}

CodePudding user response:

With java streams you can do that in that way:

var aMap = IntStream.range(0, a.length)
        .boxed()
        .collect(Collectors.toMap(i -> i, i -> a[i], (x, y) -> y));

var bMap = IntStream.range(0, b.length)
        .boxed()
        .collect(Collectors.toMap(i -> i, i -> b[i], (x, y) -> y));

var cMap = IntStream.range(0, c.length)
        .boxed()
        .collect(Collectors.toMap(i -> i, i -> c[i], (x, y) -> y));

var collect = Stream.of(aMap, bMap, cMap)
        .flatMap(map -> map.entrySet().stream())
        .collect(Collectors.groupingBy(Map.Entry::getKey))
        .values().stream()
        .flatMap(Collection::stream).map(Map.Entry::getValue).toList();
  • Related