Alternating between two arraylists.

天涯浪子 提交于 2019-12-23 04:45:48

问题


I am having trouble getting this thing to run. I'm not sure if what I have so far is on the right track. I'm not quite sure where is is giving me an out of bounds error.

Here are the instructions:

Write a method called interleave that accepts two ArrayLists of integers a1 and a2 as parameters and inserts the elements of a2 into a1 at alternating indexes. If the lists are of unequal length, the remaining elements of the longer list are left at the end of a1. For example, if a1 stores [10, 20, 30] and a2 stores [4, 5, 6, 7, 8], the call of interleave(a1, a2); should change a1 to store [10, 4, 20, 5, 30, 6, 7, 8]. If a1 had stored [10, 20, 30, 40, 50] and a2 had stored [6, 7, 8], the call of interleave(a1, a2); would change a1 to store [10, 6, 20, 7, 30, 8, 40, 50].

private static void interleave(ArrayList<Integer> a1,
        ArrayList<Integer> a2) {

    int i = a1.size();
    int j = a2.size();

    if (i < j) { // a1 is shorter than a2
        for (int k = 0; k < a1.size(); k++) { // before k passes a1 size
            a1.add(k+1, a2.get(k));
        }

        for (int l = a1.size(); l < a2.size(); l++) {
            a1.add(a1.size(), a2.get(l));
        }

    } else if (i > j) { // a1 is longer than a2
        for (int k = 1; k < a2.size(); k++) {
            a1.add(k+1, a2.get(k));
        }

    } else { // they are equal length
        for (int k = 1; k < a2.size(); k++) {
            a1.add(k+1, a2.get(k));
        }
    }
}

回答1:


This should work

private static void interleave(ArrayList<Integer> a1, ArrayList<Integer> a2) {
    int i = -1;
    for(Integer elem: a2) {
        if(i < a1.size()-1) {
            i += 2;
        } else {
            i += 1;
        }
        a1.add(i, elem);
    }
}

public static void main(String[] args) throws Exception {

    ArrayList<Integer> a1 = new ArrayList<>(Arrays.asList(10, 20, 30));
    ArrayList<Integer> a2 = new ArrayList<>(Arrays.asList(4, 5, 6, 7, 8));

    interleave(a1, a2);
    System.out.println(a1);
}

edit: I have to admit, that this code is actually a pretty bad solution, because it's gonna be very slow for long lists. Every time an element is added to a1, a big part of the list has to be shifted by one position. So following the advice from "MadProgrammer", here is a much better and much much faster way to do it

private static void interleave(ArrayList<Integer> a1, ArrayList<Integer> a2) {
    ArrayList<Integer> r = new ArrayList<>(a1.size() + a2.size());

    for(int i = 0, j = 0; i < a1.size() || j < a2.size(); i++, j++) {
        if(i < a1.size()) r.add(a1.get(i));
        if(j < a2.size()) r.add(a2.get(j));
    }
    a1.clear();
    a1.addAll(r);
}



回答2:


I see that there's already any accepted answer, but I think that this is a case where using a for loop with proper index variables will be more convenient than the for loop that works on arrays and collections. For instance, look at what happens as this progress over time. a2 is always the same: [4 5 6 7 8], and the indices of its elements that should be inserted into a1 are 0, 1, 2, 3, 4. Now, the first element (4) should be inserted into a1 at position 1. After that, the next element (5) needs to be inserted at position 3. Then 6 needs to be inserted at position 5. In general, the ith element of a2 needs to be inserted at position i*2+1 in a1. This will hold until either i*2+1 is bigger than the number of elements in a1, or you run out of elements in a2. With this taken into consideration, the proper index to insert the ith element of a2 into a1, after all the earlier elements have been inserted, is Math.min( i*2+1, l1.size() ), since adding at l1.size() just adds an element to the end of the list.

I agree with the comment about not giving away homework answers, but since there's already an answer with a complete implementation, and I want to contrast the for with an index to the for-each loop, I'll include code here. The updated interleave method is

public static <T> List<T> interleave( final List<T> l1, final List<T> l2 ) {
    for ( int i = 0; i < l2.size(); i++ ) {
        l1.add( Math.min( i*2+1, l1.size()), l2.get( i ));
    }
    return l1;
}

This isn't necessarily the most efficient implementation, though. It would make more sense to finish the for loop when you get to the end of l1 and simply add the remaining elements all at once. I've also written this to take Lists, since that's all the code depends on, though the random accessing with get will only be efficient on lists that support it efficiently (e.g., it will be fine for ArrayLists, but will perform poorly for linked lists). The fact that these are just lists also suggests that you might consider a solution using ListIterators.

In context, and with a main method that demonstrates it:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Interleave {

    public static <T> List<T> interleave( final List<T> l1, final List<T> l2 ) {
        for ( int i = 0; i < l2.size(); i++ ) {
            l1.add( Math.min( i*2+1, l1.size()), l2.get( i ));
        }
        return l1;
    }

    public static void main(String[] args) {
        final List<Integer> l1 = new ArrayList<Integer>( Arrays.asList( 10, 20, 30 ) );
        final List<Integer> l2 = Arrays.asList( 4, 5, 6, 7 ,8 );
        System.out.println( interleave( l1, l2 ));
    }
}

After thinking about this some more, I think that there's something to be said for using a ListIterator here. It makes some of the iteration and insertion code a bit cleaner, especially since insertion with a ListIterator occurs before the iteration cursor. It also doesn't require any complicated index arithmetic. Here's an implementation that uses the ListIterators:

public static <T> List<T> interleaveWithIterators( final List<T> l1, final List<T> l2 ) {
    // Get an iterator for the l1, and position it after the first element
    // or at the end, if there's no first element.
    final ListIterator<T> it1 = l1.listIterator();
    if ( it1.hasNext() ) { it1.next(); } 

    // Get an iterator for l2.  While there are elements remaining in l2, 
    // keep adding them to l1 by calling it1.add().  While there are elements
    // in l1, this also requires pushing it1 forward by one element on each iteration.
    final ListIterator<T> it2 = l2.listIterator();
    while ( it2.hasNext() ) {
        it1.add( it2.next() );
        if ( it1.hasNext() ) { it1.next(); }
    }
    return l1;
}

To avoid checking if ( it1.hasNext() ) { ... } on each iteration, you could split up the while loop:

public static <T> List<T> interleaveWithIterators( final List<T> l1, final List<T> l2 ) {
    final ListIterator<T> it1 = l1.listIterator();
    if ( it1.hasNext() ) { it1.next(); } 
    final ListIterator<T> it2 = l2.listIterator();
    while ( it2.hasNext() && it1.hasNext() ) {
        it1.add( it2.next() );
        it1.next();
    }
    while ( it2.hasNext() ) {
        it1.add( it2.next() );
    }
    return l1;
}



回答3:


This worked for me.

private static void interleave(ArrayList<Integer> 
a1, ArrayList<Integer> a2) {
int i = -1;
for(Integer elem: a2) {
    if(i < a1.size()-1) {
        i += 2;
    } else {
        i += 1;
    }
    a1.add(i, elem);
}
}

public static void main(String[] args) throws Exception {

ArrayList<Integer> a1 = new ArrayList<>(Arrays.asList(10, 20, 30));
ArrayList<Integer> a2 = new ArrayList<>(Arrays.asList(4, 5, 6, 7, 8));

interleave(a1, a2);
System.out.println(a1);
}



回答4:


public static LinkedList<Integer> alternate(LinkedList<Integer> list1, LinkedList<Integer> list2){
    List<Integer> newList = new LinkedList<Integer>();
    Iterator<Integer> itr1 = list1.iterator();
    Iterator<Integer> itr2 = list2.iterator();
    while (itr1.hasNext() || itr2.hasNext()){
        if (itr1.hasNext()){
            newList.add(itr1.next());
        }
        if (itr2.hasNext()){
            newList.add(itr2.next());
        }
    }
    return newList;
}


来源:https://stackoverflow.com/questions/19260820/alternating-between-two-arraylists

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!