Java Stream:查找具有属性的最小/最大值的元素

Jan*_*lek 19 java collections java-stream

我有一个对象流,我想找到一个具有某个属性的最大值的那个,计算起来很昂贵.

作为一个特定的简单示例,假设我们有一个字符串列表,我们希望找到最酷的一个,给定一个coolnessIndex函数.

以下应该有效:

String coolestString = stringList
        .stream()
        .max((s1, s2) -> Integer.compare(coolnessIndex(s1), coolnessIndex(s2)))
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

现在,这有两个问题.首先,假设coolnessIndex计算成本很高,这可能不会非常有效.我想这个max方法需要重复使用比较器,这反过来会coolnessIndex重复调用,最后每个字符串会多次调用它.

其次,必须提供比较器会导致代码中的一些冗余.我更喜欢这样的语法:

String coolestString = stringList
        .stream()
        .maxByAttribute(s -> coolnessIndex(s))
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

但是,我无法在StreamAPI中找到匹配的方法.这让我感到惊讶,因为通过属性查找min/max似乎是一种常见的模式.我想知道是否有比使用比较器更好的方法(除了for循环).

gus*_*stf 8

这是一个使用Object[]作为元组的变体,不是最漂亮的代码,而是简洁

String coolestString = stringList
        .stream()
        .map(s -> new Object[] {s, coolnessIndex(s)})
        .max(Comparator.comparingInt(a -> (int)a[1]))
        .map(a -> (String)a[0])
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)


frh*_*ack 8

Stream<String> stringStream = stringList.stream();
String coolest = stringStream.reduce((a,b)-> 
    coolnessIndex(a) > coolnessIndex(b) ? a:b;
).get()
Run Code Online (Sandbox Code Playgroud)


Jan*_*lek 4

谢谢大家的建议。最后我在Efficiency of the way comparator Works中找到了我最喜欢的解决方案——来自 bayou.io 的答案:

有一个通用cache方法:

public static <K,V> Function<K,V> cache(Function<K,V> f, Map<K,V> cache)
{
    return k -> cache.computeIfAbsent(k, f);
}

public static <K,V> Function<K,V> cache(Function<K,V> f)
{
    return cache(f, new IdentityHashMap<>());
}
Run Code Online (Sandbox Code Playgroud)

然后可以按如下方式使用:

String coolestString = stringList
        .stream()
        .max(Comparator.comparing(cache(CoolUtil::coolnessIndex)))
        .orElse(null);
Run Code Online (Sandbox Code Playgroud)

  • @Jan 当然,`public static &lt;K,V&gt; Function&lt;K,V&gt; cache(Function&lt;K,V&gt; f) { Map&lt;K,V&gt; cache = new IdentityHashMap&lt;&gt;(); 返回 k -&gt; cache.computeIfAbsent(k, f); }` (2认同)