Reputation: 355
Can I skip certain operations on the first stream in a lambda expression? For example
List<BeanClass> fetch = getBeanClsss();
BeanClass bean = fetch.stream().reduce(newBean, (p1,p2)-> {
p1.setVal(p1.getVal() + p2.getVal());
// if first element skip
// else
p1.setValNum(p1.getValNum() + p2.getValNum());
return p1;
});
At first element, I do not want to run p1.setValNum method but p1.setVal method to run. So I want to do everything method except the first one.
Upvotes: 4
Views: 2871
Reputation: 637
I assume you're not going to execute it in parallel stream(if you do, please be careful with p1.setValNum(p1.getValNum() + p2.getValNum())
), Here is the solution by StreamEx with fluent setters: The code is explained by itself.
StreamEx.of(fetch).mapFirst(b -> newBean.setVal(newBean.getVal() + b.getVal()))
.skip(1)
.reduce((a, b) -> a.setValNum(a.getValNum() + b.getValNum()));
BeanClass with fluent setters:
public static class BeanClass {
private int val;
private int valNum;
public int getVal() {
return val;
}
public BeanClass setVal(int val) {
this.val = val;
return this;
}
public int getValNum() {
return valNum;
}
public BeanClass setValNum(int valNum) {
this.valNum = valNum;
return this;
}
// ...
}
Upvotes: 0
Reputation: 120978
Assuming val and valNum are positive numbers and sum will not overflow:
Well if I understood correctly, than the very first time you reduce, than this will hold: p1 == newBean
. In order for the reduce to work correctly you need to respect the identity property
, what this means that newBean
has to have val
and valNum
set to zero
.
That means that if you do p1.getVal()
and see that it's zero, it means that p2
is actually the first element from your stream.
Also notice that you are violating reduce
here - you need to return a new instance from the reduce
method, something like:
.reduce(newBean, (p1, p2) -> {
BeanClass beanClass = new BeanClass();
// the first time you reduce
if(p1.getVal() == 0){
beanClass.setVal(p1.getVal() + p2.getVal());
}else {
beanClass.setVal(p1.getVal() + p2.getVal());
beanClass.setValNum(p1.getValNum() + p2.getValNum());
}
return beanClass;
})
Ultimately what you want to do is have a BeanClass
instance that has val
being equal to sum all other val from the Stream, except the first one and valNum
being equal to the sum of all valNum form the Stream. If so, streaming twice then creating the instance
is much more simpler with Misha's solution.
Upvotes: 0
Reputation: 28163
Don't use reduce
for mutable reduction. If the stream were ever made parallel, you would get unpredictable results. You didn't specify the return type of getVal
and getValNum
, so I will suppose they both return an int
. If you want to clarify your question, I will adjust the answer accordingly.
int sumVal = fetch.stream()
.mapToInt(BeanClass::getVal)
.sum();
int sumValNum = fetch.stream()
.skip(1) // now skipping the first one is straightforward!
.mapToInt(BeanClass::getValNum)
.sum();
newBean.setVal(newBean.getVal() + sumVal);
newBean.setValNum(newBean.getValNum() + sumValNum);
Upvotes: 1
Reputation: 32028
You can use skip()
over Stream
as:
fetch.stream().skip(1).reduce(newBean, (p1,p2)-> {
...perform your actions
});
Returns a stream consisting of the remaining elements of this stream after discarding the first n elements of the stream. If this stream contains fewer than n elements then an empty stream will be returned.
Upvotes: 0