Java8流收集器-根据值之和拆分列表

时间:2018-11-14 08:18:10

标签: java-8 java-stream collectors

我正在尝试根据特定字段之和应小于'x'的条件将一个列表分为多个子列表。下面是相同的代码:

public class TestGrouping {
   public static class Transaction{
     String txnId;
     String comment;
     Amount amount;

    public Transaction(String txnId, String comment, Amount amount) {
        this.txnId = txnId;
        this.comment = comment;
        this.amount = amount;
    }
}

public static class Amount{
     String amountValue;

    public Amount(String amountValue) {
        this.amountValue = amountValue;

    }
}
public static void main(String[] args) {
    List<Transaction> transactionList = new ArrayList<>();
    Transaction txn1 = new Transaction("T1","comment1",new Amount("81"));
    Transaction txn2 = new Transaction("T2","comment2",new Amount("5"));
    Transaction txn3 = new Transaction("T3","comment3",new Amount("12"));
    Transaction txn4 = new Transaction("T4","comment4",new Amount("28"));
    transactionList.add(txn1);
    transactionList.add(txn2);
    transactionList.add(txn3);
    transactionList.add(txn4);

//below is what i thought might work
//    transactionList.stream().collect(groupingBy (r->Collectors.summingInt(Integer.valueOf(r.amount.amountValue)),Collectors.mapping(t -> t, toList())));
}

目标是将transactionList分为2个(或更多)子列表-“ amount”的总和小于100。所以我可以让一个子列表只有txn1-数量为81;另一个子列表包含txn2,txn3,txn4(因为它们的总和小于100)。其他可能性是-使子列表1具有txn1,txn2,txn3;和另一个只有txn4的子列表。基本上没有尝试创建最“最佳”列表,只是金额之和应小于100。

有任何线索吗?

1 个答案:

答案 0 :(得分:0)

这个想法是使用一个自定义的收集器来生成一个对的列表(amountSum,事务),该列表应该首先进行排序。累加器方法(这里是Accumulator.accept)执行分组逻辑,我没有实现合并,因为在非并行流中不需要合并器。 下面的代码段,希望对您有所帮助。

    public class TestStream {

    public class Transaction {
        String txnId;
        String comment;
        Amount amount;

        public Transaction(String txnId, String comment, Amount amount) {
            this.txnId = txnId;
            this.comment = comment;
            this.amount = amount;
        }
    }

    public class Amount {
        String amountValue;

        public Amount(String amountValue) {
            this.amountValue = amountValue;

        }
    }

    @Test
    public void test() {
        List<Transaction> transactionList = new ArrayList<>();
        Transaction txn1 = new Transaction("T1", "comment1", new Amount("81"));
        Transaction txn2 = new Transaction("T2", "comment2", new Amount("5"));
        Transaction txn3 = new Transaction("T3", "comment3", new Amount("12"));
        Transaction txn4 = new Transaction("T4", "comment4", new Amount("28"));
        transactionList.add(txn1);
        transactionList.add(txn2);
        transactionList.add(txn3);
        transactionList.add(txn4);

        transactionList.stream()
            .sorted(Comparator.comparing(tr -> Integer.valueOf(tr.amount.amountValue)))
            .collect(ArrayList<Pair<Integer, List<Transaction>>>::new, Accumulator::accept, (x, y) -> {
            })
            .forEach(t -> {
                System.out.println(t.left);
            });
    }

    static class Accumulator {
        public static void accept(List<Pair<Integer, List<Transaction>>> lPair, Transaction tr) {
            Pair<Integer, List<Transaction>> lastPair = lPair.isEmpty() ? null : lPair.get(lPair.size() - 1);
            Integer amount = Integer.valueOf(tr.amount.amountValue);
            if (Objects.isNull(lastPair) || lastPair.left + amount > 100) {
                lPair.add(
                    new TestStream().new Pair<Integer, List<Transaction>>(amount,
                        Arrays.asList(tr)));
            } else {
                List<Transaction> newList = new ArrayList<>();
                newList.addAll(lastPair.getRight());
                newList.add(tr);
                lastPair.setLeft(lastPair.getLeft() + amount);
                lastPair.setRight(newList);
            }
        }
    }

    class Pair<T, V> {
        private T left;
        private V right;

        /**
         * 
         */
        public Pair(T left, V right) {
            this.left = left;
            this.right = right;
        }

        public V getRight() {
            return right;
        }

        public T getLeft() {
            return left;
        }

        public void setLeft(T left) {
            this.left = left;
        }

        public void setRight(V right) {
            this.right = right;
        }
    }

}