繁体   English   中英

计算java中元素的频率

[英]Count frequency of elements in java

我正在尝试计算文本文件中所有日期的频率。 日期存储在 parsed.get(0) 中,但是当我打印频率时,我得到以下输出:

1946-01-12: 1
1946-01-12: 1
1946-01-12: 1
1946-01-13: 1
1946-01-13: 1
1946-01-13: 1
1946-01-14: 1
1946-01-14: 1
1946-01-14: 1
1946-01-15: 1

代替

1946-01-12: 3
1946-01-13: 3
1946-01-14: 3
1946-01-15: 1

我想这是因为我必须存储这样的日期 ("1946-01-12", "1946-01-12", "1946-01-12", "1946-01-12", "1946-01- 13", "1946-01-13",...)。 如果我只是打印 parsed.get(0) 我得到

1946-01-12
1946-01-12
1946-01-12
1946-01-13
1946-01-13
1946-01-13
1946-01-14
1946-01-14
1946-01-14
1946-01-15`

我怎样才能根据我下面的代码解决它?

private static List<WeatherDataHandler> weatherData = new ArrayList<>();
public void loadData(String filePath) throws IOException {

//Read all data
    List<String> fileData = Files.readAllLines(Paths.get("filePath"));
    System.out.println(fileData);

    for(String str : fileData) {
        List<String> parsed = parseData(str);
        LocalDate dateTime = LocalDate.parse(parsed.get(0));

        WeatherDataHandler weather = new WeatherDataHandler(dateTime, Time, temperature, tag);
        weatherData.add(weather);

        List<String> list = Arrays.asList(parsed.get(0));

        Map<String, Long> frequencyMap =
                list.stream().collect(Collectors.groupingBy(Function.identity(), 
                                                        Collectors.counting()));

            for (Map.Entry<String, Long> entry : frequencyMap.entrySet()) {
                System.out.println(entry.getKey() + ": " + entry.getValue());
            }
    }

问题

for 循环中的所有内容都在每次迭代中执行 因此,您正在重新创建日期集合并一遍又一遍地重新创建流以进行分析。 不好。

解决方案

将流和分析代码移到for 循环之外。

将您的代码重新考虑为两个阶段。

  • 第一阶段是解析输入,将传入的数据预处理为您想要使用的形式。 在这种情况下,我们需要读取一个文本文件,将这些行解析为LocalDate对象,并将这些对象添加到一个集合中。 此代码使用 for 循环。
  • 第二阶段是处理重组数据的流工作,即LocalDate对象的集合。 此代码而来的for循环之后

在我自己的工作中,我会将这些要点作为注释放在我的代码中。 我会添加分隔线(带有一堆注释或常用符号的注释行)来标记代码中的每个阶段。 我可能会将每个阶段作为一个子程序移动到一个方法中。

顺便说一句,一旦你开始工作,为了好玩,你可能想尝试用流替换 for 循环读取文件。 Java 可以将文件作为行流读取。

我简单地测试了这个你可以检查结果

{1946-01-14=3, 1946-01-15=1, 1946-01-12=3, 1946-01-13=3}

原始文件是

1946-01-12: 1
1946-01-12: 1
1946-01-12: 1
1946-01-13: 1
1946-01-13: 1
1946-01-13: 1
1946-01-14: 1
1946-01-14: 1
1946-01-14: 1
1946-01-15: 1

随心所欲地修改它

代码:

 try {
            String content = new Scanner(new File("src/main/resources/test.txt")).useDelimiter("\\Z").next();
            String[] dates=  content.split("\\n");
            Map<String,Long> m
                    =
                    Arrays.stream(dates).
                            map(o->
                            {return o.split(":")[0];}) //not necessary if you dont have 1s in the text file
                            .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

            System.out.println(m.toString());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

有了这个,您可以获得列表中具有相同值的元素数量。

int numerOfElements = Collections.frequency(list, "1946-01-12");

根据我认为这是如何工作的,我将按如下方式进行。 包括解释附加逻辑的注释。 主要思想是在主循环中尽可能多地做。 使用stream在循环外创建frequenceyMap是额外且不必要的工作。

    private static List<WeatherDataHandler> weatherData =
            new ArrayList<>();

    public void loadData(String filePath) throws IOException {

        // Read all data
        List<String> fileData =
                Files.readAllLines(Paths.get("filePath"));
        System.out.println(fileData);

        // Pre-instantiate the freqency map.
        Map<String, Long> frequencyMap = new LinkedHashMap<>();

        for (String str : fileData) {

            List<String> parsed = parseData(str);

            LocalDate dateTime =
                    LocalDate.parse(parsed.get(0));

            WeatherDataHandler weather = new WeatherDataHandler(
                    dateTime, Time, temperature, tag);
            weatherData.add(weather);

            // Ensure dateTime is a string.  This may not have the desired
            // format for date but that can be corrected by you
            String strDate = dateTime.toString();

            // Use the compute method of Map. If the count is null,
            // initialize it to 1, otherwise, add 1 to the existing value.
            frequencyMap.compute(strDate,
                    (date, count) -> count == null ? 1 : count + 1);
        }

        for (Map.Entry<String, Long> entry : frequencyMap
                .entrySet()) {
            System.out.println(
                    entry.getKey() + ": " + entry.getValue());
        }
    }

您还可以按如下方式打印地图:

frequencyMap.forEach((k,v)->System.out.println(k + ": " + v));

最后,上面可以简化一些地方,比如使用Files.lines(path)创建流。 但是,由于您还将其写入WeatherDataHandler列表并希望保留您的结构,因此我没有使用该功能。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM