问题描述
我需要在 java 中循环多个 ArrayList。有什么简单的方法可以实现吗?
lists = [1,2,3],[4,5],[6,7,8]
结果应该是:
[1,4,6,5,3,8]
解决方法
tl;博士
循环列表列表,循环最大大小。从每个列表中提取第 n 个元素。当我们请求超出其大小的第 n 个元素时,较短的列表将引发异常;只需忽略该异常。
List < List < Integer > > listOfLists =
List.of(
List.of( 1,2,3 ),List.of( 4,5 ),List.of( 6,7,8 )
);
OptionalInt longestLength = listOfLists.stream().mapToInt( List :: size ).max();
int limit = longestLength.orElse( 0 );
int initialCapacity = listOfLists.stream().mapToInt( List :: size ).sum();
List < Integer > results = new ArrayList <>( initialCapacity );
for ( int i = 0 ; i < limit ; i++ )
{
for ( List < Integer > listOfIntegers : listOfLists )
{
try
{
Integer integer = listOfIntegers.get( i );
results.add( integer );
}
catch ( IndexOutOfBoundsException e )
{
// Do nothing. Swallow exception. We expect to fall out of bounds on shorter lists.
}
}
}
return List.copyOf( results ) ;
这种方法可能会通过检查我们是否越过较短数组的末尾而不是抛出异常来改进。但在这种情况下,我认为这没有什么意义。
详情
定义我们的列表。
List < List < Integer > > listOfLists =
List.of(
List.of( 1,8 )
);
listOfLists.toString() = [[1,3],[4,5],[6,8]]
确定列表的最长长度。
OptionalInt longestLength = listOfLists.stream().mapToInt( List :: size ).max();
int limit = longestLength.orElse( 0 );
longestLength.toString() = OptionalInt[3]
限制 = 3
建立一个列表来记录我们的结果。
int initialCapacity = listOfLists.stream().mapToInt( List :: size ).sum();
List < Integer > results = new ArrayList <>( initialCapacity );
遍历每个列表,忽略在较短列表中抛出的任何 IndexOutOfBoundsException
。
for ( int i = 0 ; i < limit ; i++ )
{
for ( List < Integer > listOfIntegers : listOfLists )
{
try
{
Integer integer = listOfIntegers.get( i );
results.add( integer );
}
catch ( IndexOutOfBoundsException e )
{
// Do nothing. Swallow exception. We expect to fall out of bounds on shorter lists.
}
}
}
看到这个code run live at IdeOne.com。
结果 = [1,4,6,5,3,8]
返回这些数字中的 unmodifiable list 个。
return List.copyOf( results ) ;
,
如果您想创建一维数组,其中填充来自锯齿状二维数组的列中的数据,您可以使用两个嵌套流:首先按列,然后按行。如果您事先不知道列数,那么您可以进行迭代,直到列仍然存在于至少一行中。
int[][] arr2 = {{1,3},{4,5},{6,8}};
int[] arr1 = IntStream
// iterate over the columns of a 2d array
.iterate(0,i -> i + 1)
// take an array of values from each column Stream<int[]>
.mapToObj(i -> Arrays
// iterate over the array rows
.stream(arr2)
// filter those rows where this column is present
.filter(row -> row.length > i)
// take value from the column
.mapToInt(row -> row[i])
// return an array
.toArray())
// until the columns are still present
.takeWhile(arr -> arr.length > 0)
// flatten to a single stream
.flatMapToInt(Arrays::stream)
// return an array
.toArray();
// output
System.out.print(Arrays.toString(arr1)); // [1,8]
另见:Efficient way to choose data from several Lists with round robin algorithm