2014-12-22 12 views
5

종종 double 또는 int 값을 생성하는 기준의 최대화에 따라 콜렉션의 최대 요소가 필요합니다. 스트림에는 max() 함수가있어 비교기를 구현해야하므로 번거롭다. 다음 예에서 names.stream().argmax(String::length)과 같이보다 간결한 구문이 있습니까? 사용arg 8 Java 스트림에서 최대?

String longestName = names.stream().max(Comparator.comparing(String::length)).get(); 

import java.util.Arrays; 
import java.util.Comparator; 
import java.util.List; 

public class ArgMax 
{ 
    public static void main(String[] args) 
    { 
     List<String> names = Arrays.asList("John","Joe","Marilyn"); 
     String longestName = names.stream().max((String s,String t)->(Integer.compare(s.length(),t.length()))).get(); 
     System.out.println(longestName); 
    } 
} 

답변

10

일부 재산에 요소를 비교 (보다 더 복잡 할 수 있지만 필요가 없습니다).

As Brian suggests in the commentsStream이 비어있는 경우 Optional#get()을 사용하면 안전하지 않습니다. Optional#orElse(Object)과 같은 더 안전한 검색 방법 중 하나를 사용하는 것이 가장 적합합니다.이 방법은 최대 값이없는 경우 일부 기본값을 제공합니다.

+6

가! 마지막에 원시'get()'을 사용하지 말라. 그렇지 않으면 스트림이 비어 있다면 NSEE를 던질 것이다. 'orElse','orElseThrow' 또는'ifPresent'와 같은 안전한 메소드를 사용하십시오. –

+5

@BrianGoetz 브라이언 알레르기 중 하나를 발견했다고 생각합니다. 그는'Optional.get()'을 작성할 때마다 재채기를합니다. –

+2

@StuartMarks 그렇습니다. 우리는 결코 그것을 'get'이라고 부르면 안된다. 우리는 그것을'getOrThrow()'또는'orElseThrow()'또는'getUnsafely()'또는 아마도'getOrThrowNoSuchElementExcpetionIfThisOptionalIsNotPresent()'로 불렀어야합니다. –

3

max/min은 고유 한 반면, 당연히 argMax/argMin은 보장 할 수 없습니다. 이것은 특히 감소 유형이 컬렉션 (예 : List)과 같아야 함을 의미합니다. 위에서 제안한 것보다 더 많은 작업이 필요합니다.

다음의 ArgMaxCollector<T> 클래스는 이러한 감소의 간단한 구현을 제공합니다. main는 클래스의 응용 프로그램이 자신의 길이에 의해 정렬 된 문자열

one two three four five six seven 

세트의 argMax/argMin을 계산하는 방법을 보여줍니다. (각각 argMaxargMin 수집 결과를보고)의 출력은 두 개의 길고 짧은 세 문자열 각각 것을

[three, seven] 
[one, two, six] 

이어야한다.

이것은 새로운 Java 8 스트림 API 사용에 대한 나의 첫 번째 시도이므로 모든 설명이 환영받을 것입니다.

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.Comparator; 
import java.util.List; 
import java.util.stream.Collector; 

class ArgMaxCollector<T> { 

    private T max = null; 
    private ArrayList<T> argMax = new ArrayList<T>(); 
    private Comparator<? super T> comparator; 

    private ArgMaxCollector(Comparator<? super T> comparator) { 
     this.comparator = comparator; 
    } 

    public void accept(T element) { 
     int cmp = max == null ? -1 : comparator.compare(max, element); 
     if (cmp < 0) { 
      max = element; 
      argMax.clear(); 
      argMax.add(element); 
     } else if (cmp == 0) 
      argMax.add(element); 
    } 

    public void combine(ArgMaxCollector<T> other) { 
     int cmp = comparator.compare(max, other.max); 
     if (cmp < 0) { 
      max = other.max; 
      argMax = other.argMax; 
     } else if (cmp == 0) { 
      argMax.addAll(other.argMax); 
     } 
    } 

    public List<T> get() { 
     return argMax; 
    } 

    public static <T> Collector<T, ArgMaxCollector<T>, List<T>> collector(Comparator<? super T> comparator) { 
     return Collector.of(
      () -> new ArgMaxCollector<T>(comparator), 
      (a, b) -> a.accept(b), 
      (a, b) ->{ a.combine(b); return a; }, 
      a -> a.get() 
     ); 
    } 
} 

public class ArgMax { 

    public static void main(String[] args) { 

     List<String> names = Arrays.asList(new String[] { "one", "two", "three", "four", "five", "six", "seven" }); 

     Collector<String, ArgMaxCollector<String>, List<String>> argMax = ArgMaxCollector.collector(Comparator.comparing(String::length)); 
     Collector<String, ArgMaxCollector<String>, List<String>> argMin = ArgMaxCollector.collector(Comparator.comparing(String::length).reversed()); 

     System.out.println(names.stream().collect(argMax)); 
     System.out.println(names.stream().collect(argMin)); 

    } 

}