首页 > 解决方案 > 使用 Java 解析 .csv 文件时面临的问题

问题描述

我有一个 .csv 文件,如下所示。它有 2 列URLtimestamp. 假设 URL 是字母数字和 UTC 日期/时间。

URL,timestamp
URL1,2018-12-09T14:19:00+00:00
URL1,2018-12-09T10:13:00+00:00
URL2,2018-12-09T07:25:00+00:00
URL3,2018-12-09T06:19:00+00:00
URL2,2018-12-08T22:03:00+00:00
URL3,2018-12-08T21:30:00+00:00
URL3,2018-12-08T09:30:00+00:00
URL2,2018-12-07T23:30:00+00:00

我想查找给定日期作为输入,访问次数最多的 URL。

eg : Input : 2018-12-09
     Output : URL1
    Explaination: We can see above that URL1 has 2 entries on 2018-12-09 ,so it was visited the most times on that day.

我实现上述的想法是使用 aHashMap<String , List<String>>来存储date as Keyand URL's as List of values for that Key

我在解析这个文件时遇到了问题。我怎样才能

  1. 解析时间戳列并将日期存储Key在地图中,因为有重复的日期?

  2. 我假设一旦我们可以缩小上述范围,我们就可以将 URL 作为值存储在该键的列表中。我们可以从映射中提取对应键的值到一个数组,然后检查大多数重复的 URL。这是正确的方法吗?

我没有为此使用任何第 3 方库

高度赞赏以上任何输入。

标签: javacsvdatetimeparsinghashmap

解决方案


我建议您创建一个自定义类型,例如Visit如下所示,以结构化方式处理记录。您可以使用标准 Java I/O 库或一些专门的库从文件中读取记录并填充Visit对象。为此,我建议您使用流行的opencsv 库。无论您以何种方式填充Visit对象并创建List<Visit>这些对象,都可以使用 Java Stream API 来处理列表。为了这个演示,我List<Visit>用你的问题中显示的记录创建了一个。

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

class Visit {
    private String url;
    private OffsetDateTime dateTime;

    public Visit(String url, OffsetDateTime dateTime) {
        this.url = url;
        this.dateTime = dateTime;
    }

    public String getUrl() {
        return url;
    }

    public OffsetDateTime getDateTime() {
        return dateTime;
    }
}

public class Main {
    public static void main(String[] args) {
        List<Visit> list = List.of(
                new Visit("URL1", OffsetDateTime.parse("2018-12-09T14:19:00+00:00")),
                new Visit("URL1", OffsetDateTime.parse("2018-12-09T10:13:00+00:00")),
                new Visit("URL2", OffsetDateTime.parse("2018-12-09T07:25:00+00:00")),
                new Visit("URL3", OffsetDateTime.parse("2018-12-09T06:19:00+00:00")),
                new Visit("URL2", OffsetDateTime.parse("2018-12-08T22:03:00+00:00")),
                new Visit("URL3", OffsetDateTime.parse("2018-12-08T21:30:00+00:00")),
                new Visit("URL3", OffsetDateTime.parse("2018-12-08T09:30:00+00:00")),
                new Visit("URL2", OffsetDateTime.parse("2018-12-07T23:30:00+00:00"))

        );

        // Tests
        System.out.println(mostVisitedUrlByDate(list, LocalDate.of(2018, 12, 9)));
        System.out.println(mostVisitedUrlByDate(list, LocalDate.now(ZoneOffset.UTC)));
        System.out.println(mostVisitedUrlByDate(null, LocalDate.of(2018, 12, 9)));
    }

    static String mostVisitedUrlByDate(List<Visit> list, LocalDate date) {
        return list!=null ? list.stream() // Traverse list if it is not null
            .filter(e -> e.getDateTime().toLocalDate().equals(date))
            // Get a Map<String, List<Visit>> where value is the list of Visit objects grouped on the URL
            .collect(Collectors.groupingBy(Visit::getUrl))
                .values()
                // Stream of values of Map obtained as a result of grouping 
                .stream()
                // Find the value i.e. List<Visit> of largest size
                .max(Comparator.comparing(List::size))
                //A List<Visit> with a default Visit object  
                .orElse(List.of(new Visit("Unknown", OffsetDateTime.now(ZoneOffset.UTC))))
                // All Visit elements in the value have same URL. Get the URL of the first value
                .get(0) 
                .getUrl()
                // Return "Unknown" if list is null
                :"Unknown";
    }
}

输出:

URL1
Unknown
Unknown

我在代码中添加了足够多的注释,以便您更容易理解。另外,我对该方法进行了三个测试调用,mostVisitedUrlByDate以便您可以清楚地了解每个方法调用的Stream目的Optional


推荐阅读