问题
I have a list of objects to be added in a bag and bags capacity is 100 qty
The Object and Bag look like below
public class MyObject{
String id;
int qty;
}
public class MyBag{
String id;
int qty;
}
Is there any way to split MyObject in multiple MyBags grouping on the qty limit using Java 8 streams
For example: myObjects are
[myObject1:{id1, 150},
myObject2:{id2, 30},
myObject3:{id3, 150}]
Since bag has a capacity of 100. Bags should be grouped as
[ bag1:[{id1, 100}],
bag2:[{id1, 50},{id2, 30},{id3, 20}],
bag3:[{id3, 100}],
bag4:[{id3, 30}]]
回答1:
As it was maintained in comments the solution won't be easy. Below is an example that is close to what you want. First I used only first class MyObject
and change it a bit.
public class MyObject{
String id;
int qty;
public MyObject(String id, int qty) {
this.id = id;
this.qty = qty;
}
@Override
public String toString() {
return "MyObject{" +
"id='" + id + '\'' +
", qty=" + qty +
'}';
}
}
Init code:
List<MyObject> myObjects = Arrays.asList(
new MyObject("id1", 150),
new MyObject("id2", 30),
new MyObject("id3", 150)
);
And the main code. In flatMap
there is splitting MyObject
with large qty
. After that objects are collected to lists with given limit. The output isn't exactly as you want. The third list includes two objects with identifier id3
.
[MyObject{id='id1', qty=100}]
[MyObject{id='id1', qty=50}, MyObject{id='id2', qty=30}, MyObject{id='id3', qty=20}]
[MyObject{id='id3', qty=80}, MyObject{id='id3', qty=20}]
[MyObject{id='id3', qty=30}]
LinkedList<List<MyObject>> firstCollection = myObjects.stream()
.flatMap(o -> o.qty < 100 ? Stream.of(o) : IntStream.range(0, (o.qty / 100 + 1))
.mapToObj(x -> new MyObject(o.id, x < o.qty / 100 ? 100 : o.qty % 100))
)
.collect(
Collector.of(
LinkedList::new,
(a, b) -> Optional.of(a).filter(Predicate.not(List::isEmpty))
.map(l -> l.getLast().stream().map(o -> o.qty).reduce(Integer::sum).get())
.filter(lastSum -> lastSum < 100)
.ifPresentOrElse(lastSum -> {
int maxQty = 100 - lastSum;
if (maxQty >= b.qty) {
a.getLast().add(b);
} else {
a.getLast().add(new MyObject(b.id, maxQty));
a.add(new ArrayList<>(List.of(new MyObject(b.id, b.qty - maxQty))));
}
}, () -> a.add(new ArrayList<>(List.of(b))))
,
(a, b) -> { throw new UnsupportedOperationException();}
)
);
firstCollection.forEach(System.out::println);
来源:https://stackoverflow.com/questions/59701676/split-a-collection-of-objects-based-on-a-condition