使用Java流获取arrayList中最小大小列表的索引

时间:2018-11-28 17:44:47

标签: java collections java-stream

我有一个整数列表的列表,例如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进行操作。

请注意,我在重型计算中多次调用此方法,因此安装者应考虑到这一点。

5 个答案:

答案 0 :(得分:5)

不太优雅,因为它需要装箱和拆箱,但是...

Optional<Integer> minIndex = 
    IntStream.range(0, list.size())
             .boxed()
             .min(Comparator.comparingInt(i -> list.get(i).size()));

答案 1 :(得分:3)

一种可能的方法是将indexOfCollections.mincomparator用作:

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.nCopiesArrays.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中打印最小列表的索引