2017-06-08 29 views
5

Chcę dowiedzieć się, który element nie spełnia predykatu w przypadku allmatch.Znajdź, który element strumienia nie pasuje do podanego predykatu w allmatch

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
boolean isEven = numbers.stream().allMatch(n-> n % 2 == 0); 

Tutaj isEven jest false, jako elementem 1 nie predykat.

mogę używać forEach nad strumieniem znaleźć który element zawiedzie jak:

numbers.stream().forEach(n -> { 
      if (n % 2 != 0) 
       System.out.println(n + "is Odd"); 
     }); 

Czy istnieje sposób, aby dowiedzieć się, które elementy nie predykat w allmatch kiedy wraca false?

Odpowiedz

5

Należy pamiętać, że allMatch jest operacją zwarcia, co oznacza, że ​​API strumienia może zwrócić wartość false bez znajdowania wszystkich elementów, które nie przejdą testu.

Jeśli więc chcesz znaleźć wszystkie wadliwych elementów, być może będziesz musiał wykonać więcej pracy niż zwykły allMatch (jak pokazują inne odpowiedzi). Jednakże, jeśli tylko dbać, aby znaleźć jeden element, który nie przejdzie testu, należy findAny następująco:

Optional<Integer> odd = numbers.stream() 
    .filter(n -> n % 2 != 0) 
    .findAny(); 

boolean isEven = !odd.isPresent(); 

odd.ifPresent(x -> System.out.println(x + " is odd")); 
5

Na tym przykładzie:

Map<Boolean, List<Integer>> map = numbers.stream() 
      .collect(Collectors.partitioningBy(x -> x % 2 == 0)); 

    System.out.println(map); // {false=[1, 3, 5], true=[2, 4]} 

mógłby się po prostu zalogować się na przykład także:

boolean isEven = numbers.stream().allMatch(n -> { 
     boolean test = n % 2 == 0; 
     if (!test) { 
      System.out.println("Failed = " + n); 
     } 
     return test; 
    }); 

Ale to może wprowadzić interesujące rezultaty, jeśli uruchomić go w parallel. Wynik byłby nie do przewidzenia. To jest isEven nadal będzie zwracać poprawny wynik, ale to, co widzisz poprzez Syso jest całkowicie nie do przewidzenia. Mogą być:

Failed = 3 
Failed = 1 
Failed = 5 

A na innej perspektywie mogą być:

Failed = 3 
+0

Dziękuję @Eugene, powinienem być bardziej szczegółowe. Zgadzam się, że to rozwiązuje dany przykład, ale tak naprawdę próbuję napisać przypadek testowy i chciałbym poznać pierwszy/dowolny element, dla którego predykat się nie powiedzie. Używałem 'forEach Assert', dzięki czemu można określić, gdzie element nie spełnia predykatu, ale nie jestem w stanie zrobić czegoś podobnego z' assert allmatch'. Czy istnieje sposób, aby znaleźć element, który zawodzi, wykonując coś w rodzaju 'assert allmatch'? – sanchitkum

+1

@sanchitkum można odwrócić logikę. Jeśli co najmniej * * nie jest jeszcze .. 'logiczna allEven = numbers.stream() filter - findAny() isPresent (!). (N> (n% 2 == 0))..' – Eugene

+2

@sanchitkum Ten 'numbers.stream() filtr (n -> (n% 2 == 0)).. findAny()' zwraca 'Optional', które mogą znajdować się na wartości, która nie powiedzie się (jeśli nie jest pusta). Ale zauważ, że 'findAny' i' findFirst' są różnymi rzeczami i mogą zwracać różne wartości, jeśli strumień jest równoległy, musisz wiedzieć, który naprawdę chcesz. – Eugene

0

Spróbuj:

List<Integer> notMatchElements = numbers.stream() 
       .filter(n -> n % 2 == 0) 
       .collect(Collectors.toList()); 

Jeśli długość notMatchElements równa 0 -> wszystkie mecze

Else -> ty nie pasuje do elementów

0

Trzeba rozdzielić tych dwóch działań (filtrowanie i weryfikacji cały mecz na dwie akcje)

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
List<Integer> notMatched = numbers 
          .stream() 
          .filter(n-> n % 2 != 0) 
          .collect(Collectors.toList()); 
boolean isEven = notMatched.isEmpty(); 
0

proponuję użyć tego podejścia:

List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 

List<Integer> badNumbers = numbers.stream().filter(n -> n % 2 != 0).collect(Collectors.toList()); 

W tym przypadku badNumbers będzie pusta, jeśli wszystkie elementy spełniają n%2 = 0 inaczej będzie zawierać wartości, które nie.

0

Coś trzeba wyjaśnić: a boolean nie jest Predicate.boolean jest rzeczownik, ale Predicate jest orzecznik. więc Predicate więcej tak:

IntPredicate isEven = n -> n % 2 == 0; 

boolean numbersAreEven = numbers.stream().allMatch(isEven); 

IF trzeba odwrócić się Predicate można korzystając Predicate#negate, na przykład:

IntPredicate isOdd = isEven.negate(); 

boolean numbersAreOdd = numbers.stream().allMatch(isOdd); 

IF chcesz wymienić wszystkie numery nieparzyste, powinieneś użyć Stream#filter, na przykład:

numbers.stream().filter(isOdd).forEach(System.out::println); 

IF chcesz znaleźć pierwszą liczbę nieparzystą, można użyć Stream#findFirst, na przykład:

Number odd = numbers.stream().filter(isOdd).findFirst().orElse(null); 

IF chcesz znaleźć pierwszą nieparzystą liczbę niezależnie od elementów zamówienia, można użyć Stream#findAny na przykład:

Number odd = numbers.stream().filter(isOdd).findAny().orElse(null); 

Uwaga: zarówno Stream#findAny i Stream#findFirstshort-circuiting terminal operation, co oznacza, że ​​w chory zjazd po spełnieniu dowolnego warunku intermediate operation.