すでに受け入れられている回答があるようですが、これは、配列やコレクションで機能for
するループよりも、適切なインデックス変数を使用したループを使用する方が便利な場合だと思います。for
たとえば、これが時間の経過とともにどのように進行するかを見てください。 a2
は常に同じです:[4 5 6 7 8]
であり、挿入される要素のインデックスa1
は0, 1, 2, 3, 4
です。ここで、最初の要素 ( )を位置4
に挿入する必要があります。その後、次の要素 ( ) を位置 に挿入する必要があります。次に、位置に挿入する必要があります。一般に、 の番目の要素は の位置に挿入する必要があります。a1
1
5
3
6
5
i
a2
i*2+1
a1
. i*2+1
これは、 の要素数よりも大きくなるか、 の要素がなくなるまで保持さa1
れa2
ます。これを考慮すると、以前のすべての要素が挿入された後、 のi
番目の要素をにa2
挿入する適切なインデックスは です。これは、 atを追加するとリストの最後に要素が追加されるだけだからです。a1
Math.min( i*2+1, l1.size() )
l1.size()
宿題の答えを渡さないというコメントには同意しますが、完全な実装の答えが既にあり、ループfor
へのインデックスと対比したいので、for-each
ここにコードを含めます。更新された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;
}
ただし、これは必ずしも最も効率的な実装ではありません。for
の最後に到達したらループを終了しl1
、残りの要素を一度に追加する方が理にかなっています。List
コードが依存するのget
はこれだけなので、私はこれを s を取るように書きましたArrayList
。 )。これらが単なるリストであるという事実は、ListIterator
sを使用した解決策を検討することも示唆しています。
コンテキスト内で、それを示すmain
方法を使用して:
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 ));
}
}
これについてもう少し考えてみると、ListIterator
ここで a を使用することについて何か言いたいことがあると思います。これにより、特に反復カーソルの前にListIterator
挿入が行われるため、反復および挿入コードの一部が少しきれいになります。また、複雑なインデックス演算も必要ありません。を使用する実装を次に示します。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;
}
各繰り返しのチェックを避けるためif ( it1.hasNext() ) { ... }
に、while ループを分割できます。
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;
}