получить индекс списка минимального размера в arrayList, используя поток Java - PullRequest
0 голосов
/ 28 ноября 2018

У меня есть список Integer List, например, 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);
    }
}

Не могли бы вы дать мне подсказку, как это сделать с помощью API потока Java.

Обратите внимание, что я вызываю этот метод много раз вТяжелое исчисление, поэтому следует принять это во внимание.

Ответы [ 5 ]

0 голосов
/ 29 ноября 2018

Держитесь подальше от решений, использующих indexOf.Хотя они могут позволять писать довольно короткий код, эта операция indexOf выполняет операцию линейного поиска на основе содержимого, вызывая equals для элементов списка до тех пор, пока не будет найдено совпадение.

Хотя это может выглядеть кактривиальная вещь, поскольку все подсписки различаются по размеру, за исключением соответствующего элемента, большинство реализаций Java 8 List не используют размер для сокращения сравнения.

Чтобы проиллюстрировать проблему,

используйте следующий вспомогательный класс

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 для любого содержащегося элемента - ненужная операция (см. первый вариант, полученный из этого ответа ), но выполненный несколько раз для других вариантов.Теперь представьте, что произойдет, если мы будем использовать большие списки и / или большее количество списков и иметь тип элемента с довольно дорогим тестом на равенство.

Обратите внимание, что для ArrayList это было решено в JDK 11,но все еще остаются реализации списка, например, возвращаемые Collections.nCopies или Arrays.asList, которые не замыкают накоротко, поэтому, как правило, предпочтительнее не выполнять полностью устаревшую контентную операцию линейного поиска.

0 голосов
/ 28 ноября 2018

Один из возможных способов сделать это - использовать indexOf и Collections.min с comparator как:

int minIndex = listOLists.indexOf(Collections.min(listOLists, 
                                   Comparator.comparingInt(List::size))); 
0 голосов
/ 28 ноября 2018

Не совсем элегантно, потому что требует бокса и распаковки, но ...

Optional<Integer> minIndex = 
    IntStream.range(0, list.size())
             .boxed()
             .min(Comparator.comparingInt(i -> list.get(i).size()));
0 голосов
/ 28 ноября 2018

Альтернатива, которая создает массивы индекса / размера и находит минимальное по размеру:

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

0 голосов
/ 28 ноября 2018

Вот один из способов:

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());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...