Java:Interleave两个基于整数的arraylists – >好方法?
家庭作业:寻找更好的策略,或者接近而不是完整的代码。
我在两个条件下有两个整数数组列表:
- 第一个列表大于第二个列表
- 第二个列表大于第一个列表
我的目标是在两种条件下将list2的元素交织到list1中。 我已经创建了一个方法来做到这一点,但我觉得我可以做得更好。
这是条件1的预期结果。请注意,在list2的元素用完之后,我们将list1的元素保留在原位:
list1: [10, 20, 30, 40, 50, 60, 70] list2: [4, 5, 6, 7] Combined: [10, 4, 20, 5, 30, 6, 40, 7, 50, 60, 70]
这是条件2的预期结果。由于list2有更多元素,因此在list1耗尽后,我们将这些元素附加到list1:
list1: [10, 20, 30, 40] list2: [4, 5, 6, 7, 8, 9, 10, 11] Combined: [10, 4, 20, 5, 30, 6, 40, 7, 8, 9, 10, 11]
我的代码使用if-else语句来处理这两个条件。 然后我使用迭代器遍历list2的元素并将它们插入list1中。
public static void main(String[] Args) { ArrayList numbers = new ArrayList(); numbers.add(10); numbers.add(20); numbers.add(30); numbers.add(40); //numbers.add(50); //numbers.add(60); //numbers.add(70); ArrayList numbers2 = new ArrayList(); 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); interleave(numbers, numbers2); System.out.println(); System.out.println("Combined: " + numbers); } public static void interleave(ArrayList list1, ArrayList list2) { //obtain an iterator for the collection Iterator itr2 = list2.iterator(); //loop counter int count = 1; //handle based on initial size of lists if(list1.size() >= list2.size()) { //loop through the first array and add elements from list 2 after each element while(itr2.hasNext()) { //insert elements from list2 list1.add(count, itr2.next()); //make sure elements are getting added at 1, 3, 5, 7, 9, etc count = count + 2; } } else if(list1.size() < list2.size()) { //loop through the first array and add elements from list 2 after each element while(itr2.hasNext()) { if(count <= list1.size()) { //insert elements from list2 list1.add(count, itr2.next()); //make sure elements are getting added at 1, 3, 5, 7, 9, etc count = count + 2; } else { //fill in the remainder of the elements from list2 to list1 list1.add(itr2.next()); } } } }
你喜欢这个解决方案吗?
public static void main(final String[] args) { ArrayList numbers = new ArrayList (); numbers.add(10); numbers.add(20); numbers.add(30); numbers.add(40); //numbers.add(50); numbers.add(60); numbers.add(70); ArrayList numbers2 = new ArrayList (); 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 interleaved = interleave(numbers, numbers2); System.out.println("\nCombined: " + interleaved); } public static List interleave( final List list1, final List list2 ) { List result = new ArrayList (list1.size() + list2.size()); Iterator it1 = list1.iterator(); Iterator it2 = list2.iterator(); while (it1.hasNext() || it2.hasNext()) { if (it1.hasNext()) { result.add(it1.next()); } if (it2.hasNext()) { result.add(it2.next()); } } return result; }
一些评论:
- 我可能会返回一个新的List而不是随意修改其中一个
- 新算法更简单:
- 创建一个新的空列表
- 循环计数器从0到两个列表的大小和交错的最小值
- 完成后,检查其中一个列表是否包含更多项目并添加它们(例如,使用
addAll
和subList
的组合) - 返回列表
- 如果您不需要改变两个原始列表,可以使用以下更短的方式声明它们:
List
– 请注意,它会创建固定大小的列表,因此您无法添加或删除numbers = Arrays.asList(10, 20, 30, 40); - 使用您当前的代码,而不是重复的东西,你可以有类似的东西:
List listSmall, listBig; if (list1.size() < list2.size()) { listSmall = list1; listBig = list2; } else { /* the opposite */}
List listSmall, listBig; if (list1.size() < list2.size()) { listSmall = list1; listBig = list2; } else { /* the opposite */}
List listSmall, listBig; if (list1.size() < list2.size()) { listSmall = list1; listBig = list2; } else { /* the opposite */}
- 然后你知道listSmall
是小的,你只需要一个循环。
这是另一种思考这个问题的方法,也是一种可以轻松扩展到3个列表的方法。
首先,要认识到这里要解决的难点是迭代,而不是创建新列表。 从iterable创建一个新列表是微不足道的。
所以想象我们有一个这样的方法:
public Iterable interleave(Iterable extends T>... lists) { return new Iterable () { @Override public Iterator iterator() { return new InterleavingIterator (lists); } }; }
我们需要做的是一个Iterator
,它一次循环遍历每个迭代器。 这对队列来说是完美的工作(fifo)! 你的迭代器看起来像这样:
class InterleavingIterator implements Iterator { private final Queue> iterators = new LinkedList<>(); public InterleavingIterator(Iterable extends T>> iteratables) { for ( Iterable iterable : iterables ) { Iterator iterator = iterable.iterator(); if ( iterator.hasNext() ) { this.iterators.add(iterator); } } } public boolean hasNext() { return !iterators.isEmpty(); } public T next() { Iterator nextIterator = iterators.poll(); T result = nextIterator.next(); if ( nextIterator.hasNext() ) { iterators.add(nextIterator); } return result; } }
简而言之,每次请求下一个元素时,弹出队列顶部的迭代器,返回next()
的结果,如果迭代器仍然有元素( hasNext()
),则将其放在后面队列。
对于任意数量的列表,这都完全相同,并且不需要任何icky条件检查。
要使用它创建新列表,您可以这样做:
List combined = new ArrayList (interleave(list1, list2));
我提出以下代码:
private static List joinTwoLists(List a, List b) { final boolean aIsBigger = a.size() > b.size(); final List 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; }