请假设我有以下数据结构
const data = [
{
key: "Item1",
value: "Item1"
},
{
key: "Item2",
value: "Item2"
},
{
key: "Item3",
value: "Item3"
}
];
class Test extends React.Component {
render() {
const pattern = new RegExp(`^${this.props.filter}$`, 'i');
const selected = (data.find((item) => pattern.test(item.key)) || {}).value;
return (
<select defaultValue={selected}>
{data.map(item => (
<option value={item.value}>{item.key}</option>
))}
</select>
);
};
}
ReactDOM.render(
<Test filter="item2" />,
demo
);
在另一种方法中,我将有一个由该类型构建的集合,如下所示:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="demo"></div>
我想将这些流映射到一个总对象
即。
看起来像这样的付款对象
public class Payment {
String paymentType;
double price;
double tax;
double total;
public Payment(String paymentType, double price, double tax, double total) {
super();
this.paymentType = paymentType;
this.price = price;
this.tax = tax;
this.total = total;
}
public String getPaymentType() {
return paymentType;
}
public void setPaymentType(String paymentType) {
this.paymentType = paymentType;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getTax() {
return tax;
}
public void setTax(double tax) {
this.tax = tax;
}
public double getTotal() {
return total;
}
public void setTotal(double total) {
this.total = total;
}
}
我知道我可以使用mapToDouble一次一列地执行此操作,但我想使用reduce或其他东西在一个流中执行此操作。
答案 0 :(得分:3)
您可以将自己的Collector
实施为Payment
对象:
Payment total =
allPayments.stream()
.collect(Collector. of(
() -> new Payment("Total", 0.0, 0.0, 0.0),
(Payment p1, Payment p2) -> {
p1.setPrice(p1.getPrice() + p2.getPrice());
p1.setTax(p1.getTax() + p2.getTax());
p1.setTotal(p1.getTotal() + p2.getTotal());
},
(Payment p1, Payment p2) -> {
p1.setPrice(p1.getPrice() + p2.getPrice());
p1.setTax(p1.getTax() + p2.getTax());
p1.setTotal(p1.getTotal() + p2.getTotal());
return p1;
}));
答案 1 :(得分:3)
没有理由使用Streams,它更短,更容易阅读:
Payment sum = new Payment("Total", 0, 0, 0);
allPayments.forEach(p -> {
sum.price += p.price;
sum.tax += p.tax;
sum.total += p.total;
});
正如评论中所讨论的,这个解决方案不仅更短更清洁(IMO),而且更易于维护:例如,现在你有一个例外:你想要继续求和所有这些属性,但你想要排除第二个索引上的项目。将它添加到reduce-verion而不是简单的for-loop是多么容易?
有趣之处在于此解决方案具有较小的内存占用(因为reduce会在每次迭代时创建一个额外的对象)并且使用提供的示例更有效地运行。
缺点:我唯一能找到的是我们处理的集合很大(数千或更多),在这种情况下我们应该使用Stream.parallel的reduce解决方案,但即便如此它应该是{ {3}}
以下列方式与JMH进行基准比较:
@Benchmark
public Payment loopIt() {
Collection<Payment> allPayments = new ArrayList<>();
allPayments.add(new Payment("Type1", 100.01, 1.12, 101.13));
allPayments.add(new Payment("Type2", 200.01, 2.12, 202.13));
allPayments.add(new Payment("Type3", 300.01, 3.12, 303.13));
allPayments.add(new Payment("Type4", 400.01, 4.12, 404.13));
allPayments.add(new Payment("Type5", 500.01, 5.12, 505.13));
Payment accum = new Payment("Total", 0, 0, 0);
allPayments.forEach(x -> {
accum.price += x.price;
accum.tax += x.tax;
accum.total += x.total;
});
return accum;
}
@Benchmark
public Payment reduceIt() {
Collection<Payment> allPayments = new ArrayList<>();
allPayments.add(new Payment("Type1", 100.01, 1.12, 101.13));
allPayments.add(new Payment("Type2", 200.01, 2.12, 202.13));
allPayments.add(new Payment("Type3", 300.01, 3.12, 303.13));
allPayments.add(new Payment("Type4", 400.01, 4.12, 404.13));
allPayments.add(new Payment("Type5", 500.01, 5.12, 505.13));
return
allPayments.stream()
.reduce(
new Payment("Total", 0, 0, 0),
(sum, each) -> new Payment(
sum.getPaymentType(),
sum.getPrice() + each.getPrice(),
sum.getTax() + each.getTax(),
sum.getTotal() + each.getTotal()));
}
<强>结果:强>
Result "play.Play.loopIt":
49.838 ±(99.9%) 1.601 ns/op [Average]
(min, avg, max) = (43.581, 49.838, 117.699), stdev = 6.780
CI (99.9%): [48.236, 51.439] (assumes normal distribution)
# Run complete. Total time: 00:07:36
Benchmark Mode Cnt Score Error Units
Play.loopIt avgt 200 49.838 ± 1.601 ns/op
Result "play.Play.reduceIt":
129.960 ±(99.9%) 4.163 ns/op [Average]
(min, avg, max) = (109.616, 129.960, 212.410), stdev = 17.626
CI (99.9%): [125.797, 134.123] (assumes normal distribution)
# Run complete. Total time: 00:07:36
Benchmark Mode Cnt Score Error Units
Play.reduceIt avgt 200 129.960 ± 4.163 ns/op
答案 2 :(得分:2)
我不会为此使用流,但是因为你问:
Payment total =
allPayments.stream()
.reduce(
new Payment("Total", 0, 0, 0),
(sum, each) -> new Payment(
sum.getPaymentType(),
sum.getPrice() + each.getPrice(),
sum.getTax() + each.getTax(),
sum.getTotal() + each.getTotal()));
答案 3 :(得分:1)
您需要BinaryOperator<Payment> accumulator
才能合并两个Payment
s:
public static Payment reduce(Payment p1, Payment p2) {
return new Payment("Total",
p1.getPrice() + p2.getPrice(),
p1.getTax() + p2.getTax(),
p1.getTotal() + p2.getTotal()
);
}
,缩减将如下:
Payment payment = allPayments.stream().reduce(new Payment(), Payment::reduce);
或(以避免创建身份对象):
Optional<Payment> oPayment = allPayments.stream().reduce(Payment::reduce);