【问题标题】:Java8 Stream Collectors - Splitting a list based on sum of valuesJava8 Stream Collectors - 根据值的总和拆分列表
【发布时间】:2019-04-17 03:39:56
【问题描述】:

我正在尝试根据特定字段的总和应小于“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())));
}

目标是将事务列表拆分为 2 个(或更多)子列表 - 其中“金额”的总和小于 100。所以我可以有一个只有 txn1 的子列表 - 金额为 81;另一个子列表有 txn2、txn3、txn4(因为这些总和小于 100)。其他可能性是 - 让 sublist1 具有 txn1、txn2、txn3;和另一个只有 txn4 的子列表。基本上不尝试创建最“最佳”的列表,只是数量总和应小于 100。

有什么线索吗?

【问题讨论】:

  • 因为你依赖于“下一个”元素,这只是一个自定义收集器的两倍 - 其中 accumulator 不会与你在普通循环中所做的有很大不同;而combiner 会更有趣-但仍然很琐碎

标签: java-8 java-stream collectors


【解决方案1】:

想法是使用自定义收集器来生成pair(amountSum, transactions)的列表,该列表最初应该是排序的。累加器方法(此处为 Accumulator.accept)执行分组逻辑,我没有实现组合,因为在非并行流中不需要组合器。 下面是代码sn-p,希望对你有帮助。

    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;
        }
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多