英文:
Limit and grouping stream
问题
我有一个实体:
public class Item {
    private String name;
    private int amount;
    private String description;
    private LocalDate reportDay;
    // 构造函数和getter、setter方法
    
}
每天我想获取过去3天的关于“Items”的信息(以报告视图显示)。我有一个仓库:
@Repository
public interface ItemRepository extends JpaRepository<Item, Long> {
    @Query(value = "SELECT item from Item item where item.reportDate >= :daysAgoDate order by item.reportDate desc")
    List<Item> findAllWithDateAfter(@Param("daysAgoDate") LocalDate daysAgoDate);
}
以及为此编写的服务:
@Service
public class ItemService {
    private final ItemRepository itemRepository;
    public List<Item> getItemsForRequiredDays(int days) {
        LocalDate daysAgoDate = LocalDate.now().minusDays(days);
        return itemRepository.findAllWithDateAfter(daysAgoDate);
    }
}
它可以正常工作。但现在我想要限制提取的行数。如果从查询中获取的items超过20个,我想要限制并按天分组。所以我想要获取只有20行(限制),并且每天只有10行(按日期分组)。
我的方法应该如下所示:
public List<Item> getItemsForRequiredDays(int days) {
    LocalDate daysAgoDate = LocalDate.now().minusDays(days);
    List<Item> items = itemRepository.findAllWithDateAfter(daysAgoDate);
    int size = items.size();
    if (size > 20) {
        return items.stream()
                .limit(20)
                .collect(Collectors.groupingBy(Item::getReportDate, Collectors.toList()))
                .values().stream()
                .flatMap(sublist -> sublist.stream().limit(10))
                .collect(Collectors.toList());
    } else {
        return items;
    }
}
如何实现这个?我在分组方面遇到了困难。
英文:
I have an entity:
public class Item {
    private String name;
    private int amount;
    private String description;
    private LocalDate reportDay;
//getters and setters with constructors
    
}
Everyday I want to get information about my Items for last 3 days (in report view). I have repository:
@Repository
public interface ItemRepository extends JpaRepository<Item, Long> {
    @Query(value = "SELECT item from Item item where item.reportDate >= :daysAgoDate order by item.reportDate desc")
    List<Item> findAllWithDateAfter(@Param("daysAgoDate") LocalDate daysAgoDate);
}
And service for this:
@Service
public class ItemService {
    private final ItemRepository itemRepository;
    public List<Item> getItemsForRequiredDays(int days) {
        LocalDate daysAgoDate = LocalDate.now().minusDays(days);
        return itemRepository.findAllWithDateAfter(daysAgoDate);
    }
}
It works okay. But now I want to limit extracted rows. If I'll get more than 20 items from my query, I want to limit and group it by days. So I want to get only 20 rows (limit), and only 10 rows for per day (groupingby)
My method should looks like:
 public List<Item> getItemsForRequiredDays(int days) {
        LocalDate daysAgoDate = LocalDate.now().minusDays(days);
        List<items> items = itemRepository.findAllWithDateAfter(daysAgoDate);
        int size = items.size();
        if (size > 20) {
            return items.stream()
                    .limit(20)
                    .collect(Collectors.groupingBy(Item::getReportDate, //here i want to group by date -> only 10 rows for each day));
        }
        else {
            return items;
        }
    }
How to do this? I'm stuck with grouping.
答案1
得分: 1
你是否想要:
return items.stream()
            .limit(20)
            .collect(Collectors.groupingBy(Item::getReportDay))
            .values().stream()
            .flatMap(items -> items.stream().limit(10))
            .collect(Collectors.toList());
这将返回多行具有多个日期的数据,每个日期最多可以出现10次。
英文:
Are you looking to:
return items.stream()
        .limit(20)
        .collect(Collectors.groupingBy(Item::getReportDay))
        .values().stream()
        .flatMap(items -> items.stream().limit(10))
        .collect(Collectors.toList());
This will return a multiple rows with multiple dates, and each date can present at max 10 times.
答案2
得分: 1
你可以按照ReportDate进行排序,然后按ReportDate进行分组。然后使用flatMap对每天的项目进行展开,每天最多限制10个项目,然后总共限制20个项目。
return items.stream()
        .sorted(Comparator.comparing(Item::getReportDate).reversed()) //如果你需要前20个项目
        .collect(Collectors.groupingBy(Item::getReportDate,
                    LinkedHashMap::new, Collectors.toList()))
        .values()
        .stream()
        .flatMap(items -> items.stream().limit(10))
        .limit(20)
        .collect(Collectors.toList());
英文:
You can sort by ReportDate then groupingBy ReportDate. Then flatten the item using flatMap limit on maximum 10 item perDay then limit 20 item only.
return items.stream()
        .sorted(Comparator.comparing(Item::getReportDate).reversed()) //If you need top 20 
        .collect(Collectors.groupingBy(Item::getReportDate,
                    LinkedHashMap::new, Collectors.toList()))
        .values()
        .stream()
        .flatMap(items -> items.stream().limit(10))
        .limit(20)
        .collect(Collectors.toList());
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论