我有一个整数列表的列表,例如list1 =(1,2,3)和list2 =(0,1)。
我的列表列表包含list1和list2。它可以包含更多内容,但在示例中,我仅列出了两个列表。
问题是使用Java流获取具有最小大小的列表的索引。
这是我的程序,它仅使用for循环方法。
import java.util.ArrayList;
public class Example {
public static void main( String[] args ) {
ArrayList<Integer> list1 = new ArrayList<>();
list1.add(1);list1.add(2);list1.add(3);
ArrayList<Integer> list2 = new ArrayList<>();
list2.add(0);list2.add(1);
ArrayList<ArrayList<Integer>> listOLists = new ArrayList<>();
listOLists.add(list1);
listOLists.add(list2);
printTheIndexOfTheListWithTheMinSize(listOLists);
}
private static void printTheIndexOfTheListWithTheMinSize( ArrayList<ArrayList<Integer>> listOLists ) {
int minSize = listOLists.get(0).size();
int minIndex = 0;
int i=0;
for ( ArrayList<Integer> list: listOLists ) {
if (list.size()<minSize)
{
minSize = list.size();
minIndex=i;
}
i++;
}
System.out.println(minIndex);
}
}
能否给我一个提示,说明如何使用Java流API进行操作。
请注意,我在重型计算中多次调用此方法,因此安装者应考虑到这一点。
答案 0 :(得分:5)
不太优雅,因为它需要装箱和拆箱,但是...
Optional<Integer> minIndex =
IntStream.range(0, list.size())
.boxed()
.min(Comparator.comparingInt(i -> list.get(i).size()));
答案 1 :(得分:3)
一种可能的方法是将indexOf
和Collections.min
和comparator
用作:
int minIndex = listOLists.indexOf(Collections.min(listOLists,
Comparator.comparingInt(List::size)));
答案 2 :(得分:3)
远离使用indexOf
的解决方案。尽管它们可能允许编写较短的代码,但此indexOf
操作带有基于内容的线性搜索操作,在列表元素上调用equals
直到找到匹配项。
虽然看起来很琐碎,因为所有子列表的大小都不同,除了匹配的元素外,大多数Java 8的List
实现都不使用该大小来简化比较。< / p>
为说明问题,
使用以下帮助程序类
class Counter {
int count;
@Override
public boolean equals(Object obj) {
count++;
return super.equals(obj);
}
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return "equals invoked "+count+" times";
}
}
和
Counter c = new Counter();
List<List<Counter>> list = Arrays.asList(
new ArrayList<>(Collections.nCopies(10, c)),
new ArrayList<>(Collections.nCopies(15, c)),
new ArrayList<>(Collections.nCopies(7, c)),
new ArrayList<>(Collections.nCopies(10, c))
);
Comparator<List<?>> cmp = Comparator.comparingInt(List::size);
System.out.println("using IntStream.range(0, list.size()).boxed()\r\n" +
" .min(Comparator.comparing(list::get, cmp))");
int minIndex =
IntStream.range(0, list.size()).boxed()
.min(Comparator.comparing(list::get, cmp)).orElse(-1);
System.out.println("result "+minIndex+", "+c);
c.count = 0;
System.out.println("\nusing list.indexOf(Collections.min(list, cmp))");
minIndex = list.indexOf(Collections.min(list, cmp));
System.out.println("result "+minIndex+", "+c);
c.count = 0;
System.out.println("\nusing list.indexOf(list.stream().min(cmp).get())");
minIndex = list.indexOf(list.stream().min(cmp).get());
System.out.println("result "+minIndex+", "+c);
它将打印
using IntStream.range(0, list.size()).boxed()
.min(Comparator.comparing(list::get, cmp))
result 2, equals invoked 0 times
using list.indexOf(Collections.min(list, cmp))
result 2, equals invoked 14 times
using list.indexOf(list.stream().min(cmp).get())
result 2, equals invoked 14 times
在Java 8中的,表明对任何包含的元素调用equals
是不必要的操作(请参阅从this answer派生的第一个变体),但对其他变体执行了多次。现在想象一下,如果我们使用更大的列表和/或更大数量的列表,并且具有相当昂贵的相等性测试的元素类型,将会发生什么情况。
请注意,对于ArrayList
,这已在JDK 11中解决,但是仍然存在列表实现,例如Collections.nCopies
或Arrays.asList
返回的实现,它们不会短路,因此通常最好不要完全基于内容进行线性搜索操作。
答案 3 :(得分:2)
这是解决问题的一种方法:
int index = listOLists.indexOf(listOLists.stream()
.min(Comparator.comparingInt(List::size))
.orElseGet(ArrayList::new));
或者如果要避免在源为空时创建ArrayList
,则可以执行以下操作:
int index = listOLists.isEmpty() ? -1 : listOLists.indexOf(listOLists.stream()
.min(Comparator.comparingInt(List::size)).get());
答案 4 :(得分:0)
创建索引/大小数组并按大小查找最小值的替代方法:
IntStream.range(0, listOLists.size())
.mapToObj(i -> new int[] { i, listOLists.get(i).size() })
.min(Comparator.comparingInt(arr -> arr[1]))
.map(arr -> arr[0])
.ifPresent(System.out::println);
这将在listOLists
中打印最小列表的索引