下面是它的名称
BigDecimal totalShare = orders.stream().map(c -> Pairing.keyLeft(c.getCompany().getId(), c.getShare())).distinct().map(Pairing::getRightItem).reduce(BigDecimal.ZERO, (x,y) -> x.add(y));
这是配对类
public final class Pairing<X,Y> {
private final X item1;
private final Y item2;
private final KeySetup keySetup;
private static enum KeySetup {LEFT,RIGHT,BOTH};
private Pairing(X item1, Y item2, KeySetup keySetup) {
this.item1 = item1;
this.item2 = item2;
this.keySetup = keySetup;
}
public X getLeftItem() {
return item1;
}
public Y getRightItem() {
return item2;
}
public static <X,Y> Pairing<X,Y> keyLeft(X item1, Y item2) {
return new Pairing<X,Y>(item1, item2, KeySetup.LEFT);
}
public static <X,Y> Pairing<X,Y> keyRight(X item1, Y item2) {
return new Pairing<X,Y>(item1, item2, KeySetup.RIGHT);
}
public static <X,Y> Pairing<X,Y> keyBoth(X item1, Y item2) {
return new Pairing<X,Y>(item1, item2, KeySetup.BOTH);
}
public static <X,Y> Pairing<X,Y> forItems(X item1, Y item2) {
return keyBoth(item1, item2);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
if (keySetup.equals(KeySetup.LEFT) || keySetup.equals(KeySetup.BOTH)) {
result = prime * result + ((item1 == null) ? 0 : item1.hashCode());
}
if (keySetup.equals(KeySetup.RIGHT) || keySetup.equals(KeySetup.BOTH)) {
result = prime * result + ((item2 == null) ? 0 : item2.hashCode());
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pairing<?,?> other = (Pairing<?,?>) obj;
if (keySetup.equals(KeySetup.LEFT) || keySetup.equals(KeySetup.BOTH)) {
if (item1 == null) {
if (other.item1 != null)
return false;
} else if (!item1.equals(other.item1))
return false;
}
if (keySetup.equals(KeySetup.RIGHT) || keySetup.equals(KeySetup.BOTH)) {
if (item2 == null) {
if (other.item2 != null)
return false;
} else if (!item2.equals(other.item2))
return false;
}
return true;
}
}
更新:
测试了斯图尔特下面的功能,它似乎工作很好。下面的操作区分每个字符串的第一个字母。我想要弄清楚的是,ConcurrentHashMap如何只为整个流维护一个实例
public class DistinctByKey {
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
public static void main(String[] args) {
final ImmutableList<String> arpts = ImmutableList.of("ABQ","ALB","CHI","CUN","PHX","PUJ","BWI");
arpts.stream().filter(distinctByKey(f -> f.substring(0,1))).forEach(s -> System.out.println(s));
}
输出为...
ABQ
CHI
PHX
BWI
Distinct
操作是一个有状态的流水线操作;在本例中,它是一个有状态的过滤器。自己创建这些有点不方便,因为没有内置的东西,但是一个小的helper类应该可以做到这一点:
/**
* Stateful filter. T is type of stream element, K is type of extracted key.
*/
static class DistinctByKey<T,K> {
Map<K,Boolean> seen = new ConcurrentHashMap<>();
Function<T,K> keyExtractor;
public DistinctByKey(Function<T,K> ke) {
this.keyExtractor = ke;
}
public boolean filter(T t) {
return seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
我不知道您的领域类,但我认为,有了这个helper类,您可以像下面这样做:
BigDecimal totalShare = orders.stream()
.filter(new DistinctByKey<Order,CompanyId>(o -> o.getCompany().getId())::filter)
.map(Order::getShare)
.reduce(BigDecimal.ZERO, BigDecimal::add);
不幸的是,类型推断在表达式中不能得到足够的深入,所以我不得不显式地为DistinctByKey
类指定类型参数。
可以去掉k
类型参数,因为除了存储在映射中之外,它实际上并不用于其他任何用途。因此object
就足够了。
/**
* Stateful filter. T is type of stream element.
*/
static class DistinctByKey<T> {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
Function<T,Object> keyExtractor;
public DistinctByKey(Function<T,Object> ke) {
this.keyExtractor = ke;
}
public boolean filter(T t) {
return seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
}
BigDecimal totalShare = orders.stream()
.filter(new DistinctByKey<Order>(o -> o.getCompany().getId())::filter)
.map(Order::getShare)
.reduce(BigDecimal.ZERO, BigDecimal::add);
这稍微简化了事情,但我仍然必须为构造函数指定类型参数。尝试使用diamond或静态工厂方法似乎并不能改善事情。我认为困难在于,当构造函数或静态方法调用在方法引用的实例表达式中时,编译器无法推断泛型类型参数。哦好吧。
(可能会简化它的另一个变体是使DistinctByKey
并将方法重命名为Eval
。这将消除使用方法引用的需要,并可能改进类型推断。但是,它不可能像下面的解决方案那么好。)
public static <T> Predicate<T> distinctByKey(Function<? super T,Object> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
BigDecimal totalShare = orders.stream()
.filter(distinctByKey(o -> o.getCompany().getId()))
.map(Order::getShare)
.reduce(BigDecimal.ZERO, BigDecimal::add);
问题内容: 我经常遇到Java lambda表达式的问题,当我想对对象的任意属性或方法上的stream()进行区分(但要保留该对象而不是将其映射到该属性或方法上)时,就会遇到问题。我开始创建容器,如这里讨论的那样,但是我开始做足够的工作,直到它变得令人讨厌并制作了许多样板课程。 我把这个Pairing类放在一起,它包含两种类型的两个对象,并允许你指定从左,右或两个对象上抠出的键。我的问题是……在某
问题内容: 我将如何在Python中“按任意键”(或抓住菜单选项)? raw_input要求您按回车键。 Windows msvcrt具有getch()和getche()。 有使用标准库执行此操作的可移植方法吗? 问题答案:
我们正在AWS上托管Cassandra 2.0.2群集。我们最近开始通过引导新节点和停用旧节点,从普通驱动器升级到SSD驱动器。除了两个节点永远处于退役状态外,进展相当顺利。现在,在新的6个节点运行后,我们注意到一些使用phpcassa的旧工具停止工作。安全组没有任何变化,所有端口TCP/UDP都是打开的,telnet可以通过9160连接,cqlsh可以“使用”群集,选择数据,但是,“描述群集”失
我使用Apache Spark 2.2.0和Scala。 我以这个问题为指导,在不使用pivot函数的情况下透视数据帧。 我需要在不使用pivot函数的情况下透视数据帧,因为我有非数字数据,而< code>pivot只对数字数据使用聚合函数,如< code>sum 、< code>min 、< code>max。我想在< code>pivot聚合中使用一个非数字列。 这是我的数据: 我希望它按<
在React中键的意义是什么?我读到在循环中使用索引不是键的最佳解决方案。为什么啊?
我正在从我的go程序向API发出http请求。请求正文是一个 JSON 对象,如下所示: 其中XXXXXXXX-XXXX-XXXX-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 如何定义一个允许该部分接