从列表对象创建一个sortedmap,其值表示为n个最低对象的列表列表的列表,映射到特定键

发布于 2025-01-31 04:38:27 字数 1131 浏览 4 评论 0原文

我正在使用一个CSV文件,其中包括有关事故的一些信息。

我已经创建了事故类型:

private Integer driverAge;
private Integer vehicleAge;

public Accident(Integer driverAge, Integer vehicleAge) {
    this.driverAge = driverAge;
    this.vehicleAge = vehicleAge;
}

我还创建了一个读取所有CSV文件的函数,将所有事故转换为list< atest>并将其保存到此类型意外结构

private List<Accident> accidents;

public AccidentArchive(List<Accident> accidents) {
    this.accidents = accidents;
}

因此,我们正在使用我尚不完全理解的流,​​并且我一直在练习中,我必须制作返回sortedmap&lt的函数; k,v&gt;,其中必须是drigrage值,并且值必须为 list n最低车辆车辆 值值:

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream().
...

我尝试使用collector.tomap() and collector.tolist()以某种方式使它起作用,但我不知道该怎么做。

I am working with a CSV file which includes some information about accidents.

I've created the Accident type:

private Integer driverAge;
private Integer vehicleAge;

public Accident(Integer driverAge, Integer vehicleAge) {
    this.driverAge = driverAge;
    this.vehicleAge = vehicleAge;
}

I've also created a function that reads all the CSV file, converts all the accidents to a List<Accident> and saves it to this type AccidentArchive:

private List<Accident> accidents;

public AccidentArchive(List<Accident> accidents) {
    this.accidents = accidents;
}

So, we are working with streams which I don't understand entirely yet, and I've been stuck in this exercise where I have to make a function that returns a SortedMap<K, V> in which the key has to be the driverAge values and the value has to be a list sorted in descending order of the n lowest vehicleAge values with the same driverAge value:

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream().
...

I have tried using Collectors.toMap() and Collectors.toList() to somehow make it work, but I have no idea how to do it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

蔚蓝源自深海 2025-02-07 04:38:27

简化方法

此问题与通过部分排序查找n最大值(或最小)值的算法问题相关。它是使用收藏家的实施似乎很难的,因此我决定引入简化的解决方案。

我们可以使用

  • A classifier function
  • a 供应商 mapfactory(允许指定结果类型地图)
  • 下游收集器

作为groupingby()的下游收集器,我们可以使用collectors mapping> mapping() and code> and code> tolist()代码>和a 函数将对映射到每个 key 的整个结果列表进行排序,然后将删除仅保留n最低Vehicleage :

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream()
        .collect(Collectors.groupingBy(Accident::getDriverAge,
            TreeMap::new,
            Collectors.collectingAndThen(
                Collectors.mapping(Accident::getVehicleAge, Collectors.toList()),
                list -> list.stream()
                    .sorted(Comparator.reverseOrder())
                    .limit(n)
                    .collect(Collectors.toList()))));
}

我之前说过的更多性能版本

,我们不需要对映射到每个的所有值进行排序。与列表的总尺寸相比,n是矮人(例如3 to 100,000每个键),这将导致严重的性能命中。

我们可以使用PriorityQueue(这是JDK中内置的HEAP数据结构的实现)来引入部分分类。

为了增强先前的解决方案,我们需要替换groupingby()的下游收集器,您可以使用mapping()自定义收集器由Priorityqueue支持,该>仅保留n最低vericleage与每个driverage

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream()
        .collect(Collectors.groupingBy(Accident::getDriverAge,
            TreeMap::new,
            Collectors.mapping(Accident::getVehicleAge, 
                getMaxN(n, Comparator.<Integer>reverseOrder()))));
}

:负责根据所得列表的提供的最大大小和A 比较器来生成自定义收集器

public static <T> Collector<T, ?, List<T>> getMaxN(int size, Comparator<T> comparator) {
        
    return Collector.of(
        () -> new PriorityQueue<>(comparator),
        (Queue<T> queue, T next) -> tryAdd(queue, next, comparator, size),
        (Queue<T> left, Queue<T> right) -> {
            right.forEach(next -> tryAdd(left, next, comparator, size));
            return left;
        },
        (Queue<T> queue) -> queue.stream().toList(),
        Collector.Characteristics.UNORDERED);
}
    
public static <T> void tryAdd(Queue<T> queue, T next, Comparator<T> comparator, int size) {
    if (queue.size() == size && comparator.compare(next, queue.element()) < 0) queue.remove(); // if next value is less than the smallest element in the queue and max size has been exceeded the largest element needs to be removed from the queue
    if (queue.size() < size) queue.add(next);
}

,分配没有指定使用sortedmap作为返回类型的要求。最好使用navigableMap接口,该接口定义了更广泛的方法。

Simplified approach

This problem correlates with the algorithmic question of finding N maximum (or minimum) values via partial sorting. It's implementation using collectors might seem tough, therefore I've decided to introduce a simplified solution.

We can use a flavor of groupingBy() that expects three arguments:

  • a classifier function,
  • a supplier mapFactory (which allows to specify the resulting type of map)
  • and a downstream collector.

As a downstream collector of groupingBy() we can utilize collectingAndThen with a combination of collectors mapping() and toList() and a function that will sort the whole resulting list mapped to each key, and then will drop unnecessary values retaining only n lowest vehicleAge:

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream()
        .collect(Collectors.groupingBy(Accident::getDriverAge,
            TreeMap::new,
            Collectors.collectingAndThen(
                Collectors.mapping(Accident::getVehicleAge, Collectors.toList()),
                list -> list.stream()
                    .sorted(Comparator.reverseOrder())
                    .limit(n)
                    .collect(Collectors.toList()))));
}

More performant version

As I've said before, we don't need to sort all values mapped to each key when we need only some of them. When n is dwarfish in comparison to the total size of the list (like 3 to 100,000 for every key) it will cause a serious performance hit.

We can introduce a partial sorting by using PriorityQueue (which is an implementation of the Heap data structure built-in in the JDK).

To enhance the previous solution, we need to replace the downstream collector of groupingBy() you can utilize a combination of mapping() and a custom collector backed by the PriorityQueue which retain only n lowest vehicleAge values associated with each driverAge:

public SortedMap<Integer, List<Integer>> getNMinVehicleAgesPerDriverAge(Integer n) {
    return getAccidents().stream()
        .collect(Collectors.groupingBy(Accident::getDriverAge,
            TreeMap::new,
            Collectors.mapping(Accident::getVehicleAge, 
                getMaxN(n, Comparator.<Integer>reverseOrder()))));
}

The method provided below is responsible for generating a custom collector based on the provided maximum size of the resulting list and a comparator. The logic behind it was explained in great detail in this answer:

public static <T> Collector<T, ?, List<T>> getMaxN(int size, Comparator<T> comparator) {
        
    return Collector.of(
        () -> new PriorityQueue<>(comparator),
        (Queue<T> queue, T next) -> tryAdd(queue, next, comparator, size),
        (Queue<T> left, Queue<T> right) -> {
            right.forEach(next -> tryAdd(left, next, comparator, size));
            return left;
        },
        (Queue<T> queue) -> queue.stream().toList(),
        Collector.Characteristics.UNORDERED);
}
    
public static <T> void tryAdd(Queue<T> queue, T next, Comparator<T> comparator, int size) {
    if (queue.size() == size && comparator.compare(next, queue.element()) < 0) queue.remove(); // if next value is less than the smallest element in the queue and max size has been exceeded the largest element needs to be removed from the queue
    if (queue.size() < size) queue.add(next);
}

By the way, if your assignment doesn't specify the requirement to utilize SortedMap as a return type. It better to use NavigableMap interface, which defines a wider range of methods, instead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文