Java: Interleave two integer based arraylists -> good approach?

后端 未结 5 636
萌比男神i
萌比男神i 2021-01-28 23:18

Homework: Looking for better strategy, or approach rather than complete code.

I\'v got two arrayLists of integers under two conditions:

  1. th
相关标签:
5条回答
  • 2021-01-28 23:54

    I propose the following code:

    private static List<Integer> joinTwoLists(List<Integer> a, List<Integer> b) {
        final boolean aIsBigger = a.size() > b.size();
        final List<Integer> joined = new ArrayList<>(aIsBigger ? a : b);
        final AtomicInteger index = new AtomicInteger(1);
        for (Integer value : aIsBigger ? b : a) {
            joined.add(index.getAndAdd(2), value);
        }
        return joined;
    }
    
    0 讨论(0)
  • 2021-01-28 23:57

    A few comments:

    • I would probably have returned a new List instead of arbitrarily modifying one of them
    • The new algorithm is then simpler:
      • create a new empty list
      • loop on a counter from 0 to the min of the two lists' sizes and interleave
      • when you are done, check if one of the lists has more items and add them (for example with a combination of addAll and subList)
      • return the list
    • If you don't need to mutate the two original lists, you can declare them in a shorter way with: List<Integer> numbers = Arrays.asList(10, 20, 30, 40); - note that it creates a fixed-size list so you can't add or remove
    • With your current code, instead of duplicating things you could have something like: List listSmall, listBig; if (list1.size() < list2.size()) { listSmall = list1; listBig = list2; } else { /* the opposite */} - then you know that listSmall is the small one and you only need one loop.
    0 讨论(0)
  • 2021-01-28 23:57

    Here's another way of thinking about this problem, and a way that would just as easily extend to 3 lists.

    First, recognize that the hard part to solve here is iteration, not creating the new list. Creating a new list from an iterable is trivial.

    So imagine we have a method like this:

    public <T> Iterable<T> interleave(Iterable<? extends T>... lists) {
        return new Iterable<T>() {
           @Override
           public Iterator<T> iterator() {
               return new InterleavingIterator<T>(lists);
           }
        };
    }
    

    What we need to make is an Iterator<T> that cycles through each iterator one at a time. That's the perfect job for a queue (fifo)! Your iterator could look something like this:

    class InterleavingIterator<T> implements Iterator<T> {
    
        private final Queue<Iterator<? extends T>> iterators = new LinkedList<>();
    
        public InterleavingIterator(Iterable<? extends T>> iteratables) {
            for ( Iterable<T> iterable : iterables ) {
               Iterator<T> iterator = iterable.iterator();
               if ( iterator.hasNext() ) {
                  this.iterators.add(iterator);
               }
            }
        }
    
        public boolean hasNext() {
            return !iterators.isEmpty();
        }
    
        public T next() {
            Iterator<T> nextIterator = iterators.poll();
            T result = nextIterator.next();
            if ( nextIterator.hasNext() ) {
               iterators.add(nextIterator);
            }
            return result;
        }
    }
    

    In short, every time the next element is requested, the iterator at the top of the queue is popped, the result of next() is returned, and if the iterator still has elements (hasNext()) it is put to the back of the queue.

    This works exactly the same for any number of lists, and doesn't need any icky condition checking.

    To create a new list with it, you could just do:

    List<Integer> combined = new ArrayList<Integer>(interleave(list1, list2));
    
    0 讨论(0)
  • 2021-01-28 23:58

    This is my approach.

    public static void interleave(ArrayList<Integer> a1, ArrayList<Integer> a2) {
        int start = 0;
        int i;
        int size = a1.size();
        for (i = 1; i < a1.size(); i += 2) {
            if (start < a2.size()) {
                a1.add(i, a2.get(start++));
            }
        }
        while (a1.size() < (size + a2.size())) {
            a1.add(i++, a2.get(start++));
        }
    
    }
    
    0 讨论(0)
  • 2021-01-29 00:05

    Do you like this solution?

    public static void main(final String[] args) {
        ArrayList<Integer> numbers = new ArrayList<Integer>();
        numbers.add(10); numbers.add(20); numbers.add(30); numbers.add(40);
        //numbers.add(50); numbers.add(60); numbers.add(70);
    
        ArrayList<Integer> numbers2 = new ArrayList<Integer>();
        numbers2.add(4); numbers2.add(5); numbers2.add(6); numbers2.add(7);
        numbers2.add(8); numbers2.add(9); numbers2.add(10); numbers2.add(11);
    
        System.out.println("list1: " + numbers);
        System.out.println("list2: " + numbers2);
        List<Integer> interleaved = interleave(numbers, numbers2);
    
        System.out.println("\nCombined: " + interleaved);
    }
    
    public static List<Integer> interleave(
        final List<Integer> list1,
        final List<Integer> list2
    ) {
        List<Integer> result
            = new ArrayList<Integer>(list1.size() + list2.size());
    
        Iterator<Integer> it1 = list1.iterator();
        Iterator<Integer> it2 = list2.iterator();
        while (it1.hasNext() || it2.hasNext()) {
            if (it1.hasNext()) {
                result.add(it1.next());
            }
            if (it2.hasNext()) {
                result.add(it2.next());
            }
        }
        return result;
    }
    
    0 讨论(0)
提交回复
热议问题