Java 用流将列表汇总到一个极限

Java 用流将列表汇总到一个极限,java,java-8,java-stream,Java,Java 8,Java Stream,如何获取记录,哪些计数总和应在限制范围内。在下面的示例中,有记录对象包含recordId和count,我想根据count的总和获取记录数据,该总和应小于或等于我的限制条件 公共类记录{ 私有int-recordID; 私人整数计数; 公共记录(整数记录ID、整数计数){ this.recordID=recordID; this.count=计数; } public int getRecordID(){ 返回recordID; } 公共无效setRecordID(int-recordID){ th

如何获取记录,哪些计数总和应在限制范围内。在下面的示例中,有
记录
对象包含recordId和count,我想根据count的总和获取记录数据,该总和应小于或等于我的限制条件

公共类记录{
私有int-recordID;
私人整数计数;
公共记录(整数记录ID、整数计数){
this.recordID=recordID;
this.count=计数;
}
public int getRecordID(){
返回recordID;
}
公共无效setRecordID(int-recordID){
this.recordID=recordID;
}
public int getCount(){
返回计数;
}
公共无效集合计数(整数计数){
this.count=计数;
}
}
公共静态void main(字符串[]args){
最终列表记录列表=新的ArrayList();
记录列表。添加(新记录(100,10));
记录列表。添加(新记录(501,20));
记录列表。添加(新记录(302,5));
记录列表。添加(新记录(405,2));
记录列表。添加(新记录(918,8));
整数极限=35;
}
预期结果
recordList
应该有记录对象:[100,10],[500,20],[302,5]记录

使用流API解决这一问题的问题是,您必须将一些信息保留在处理上下文之外,并同时对其进行读取/更新(依赖)。这些任务不适用于流API

使用一个适用于此的for循环:

int index = 0;                              // highest index possible
int sum = 0;                                // sum as a temporary variable
for (int i=0; i<recordList.size(); i++) {   // for each Record
    sum += recordList.get(i).getCount();    // ... add the 'count' to the 'sum'
    if (sum <= limit) {                     // ... until the sum is below the limit
        index = i;                          // ... move the pivot
    } else break;                           // ... or else stop processing
}

// here you need to get the list from 0 to index+1 
// as long as the 2nd parameter of subList(int, int) is exlcusive
List<Record> filteredRecords = recordList.subList(0, index + 1);
int index=0;//可能的最高索引
整数和=0;//sum作为临时变量

对于(int i=0;i这是我唯一能想到的事情,但它没有常规循环那么有效,因为它为它拥有的每个列表项运行。这也会导致它进一步向下添加其他值。例如,如果limit为46,则将跳过计数为5的第三个项,但下一个计数为2的项仍将被添加。不知道这是否为i这是你想要的行为

    AtomicInteger count = new AtomicInteger();

    recordList = recordList.stream().filter(r -> {
        if(count.get() + r.count <= limit){
            count.addAndGet(r.count);
            return true;
        }
        return false;
    }).collect(Collectors.toList());
AtomicInteger count=新的AtomicInteger();
recordList=recordList.stream().filter(r->{

如果(count.get()+r.count将以下
toString
添加到类中以进行打印,则可以按如下操作:

public String toString() {
    return String.format("[%s, %s]", recordID, count);
}
  • 分配一个列表来存储结果
  • 初始化总和
  • 遍历列表,对计数求和,直到 达到临界点

使用java 8,您可以执行以下操作:

public static void main(String[] args) {
        int limit = 35;
        List<Records> recordList = new ArrayList<>();
        recordList.add(new Records(100, 10));
        recordList.add(new Records(501, 20));
        recordList.add(new Records(302, 5));
        recordList.add(new Records(405, 2));
        recordList.add(new Records(918, 8));

        List<Records> limitedResult = recordList.stream().filter(new Predicate<Records>() {
            int sum = 0;
            @Override
            public boolean test(Records records) {
                sum=sum+records.getCount();
                return sum <= limit;
            }
        }).collect(Collectors.toList());
        //do what do you want with limitedResult
        System.out.println(limitedResult);
    }

我认为流操作不适合这种情况。老式的
while
循环就可以了。函数编程中的函数(流使用)被认为是无状态的。您的任务要求您记住一个状态。只需使用常规循环,这里没有流的好处。@f1sh在正确的函数式编程中,这将是一个前缀扫描操作,后跟一个zip和一个“take while”。问题是流只读取一次抽象。这是这里的问题,而不是函数式编程。也就是说,它仍然可以作为缩减或收集器来完成。我从这次讨论中学到了很多东西!下面的帖子可能也会有所帮助(我不认为它是重复的,因为它更一般)-你可能会发现这很有趣:)这并不能保证工作,因为谓词等根据契约是无状态的。流可能会无序消费等。只有收集器才允许有状态。
[100, 10]
[501, 20]
[302, 5]
public static void main(String[] args) {
        int limit = 35;
        List<Records> recordList = new ArrayList<>();
        recordList.add(new Records(100, 10));
        recordList.add(new Records(501, 20));
        recordList.add(new Records(302, 5));
        recordList.add(new Records(405, 2));
        recordList.add(new Records(918, 8));

        List<Records> limitedResult = recordList.stream().filter(new Predicate<Records>() {
            int sum = 0;
            @Override
            public boolean test(Records records) {
                sum=sum+records.getCount();
                return sum <= limit;
            }
        }).collect(Collectors.toList());
        //do what do you want with limitedResult
        System.out.println(limitedResult);
    }
    //Reusable predicate
    public static Predicate<Records> limitRecordPredicate(int limit){
        return new Predicate<Records>() {
            int sum = 0;
            @Override
            public boolean test (Records records){
                sum = sum + records.getCount();
                return sum <= limit;
            }
        };
    }
List<Records> limitedResult = recordList.stream().filter(limitRecordPredicate(limit)).collect(Collectors.toList());
        //do what do you want with limitedResult
        System.out.println(limitedResult);
[Records[recordID=100, count=10], Records[recordID=501, count=20], Records[recordID=302, count=5]]