【问题标题】:Count frequency of elements in javajava中元素的计数频率
【发布时间】:2020-03-03 15:40:02
【问题描述】:

我正在尝试计算文本文件中所有日期的频率。日期存储在 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());
            }
    }

【问题讨论】:

  • 你在逐行数数!
  • 如何将所有日期存储在一行中?
  • 创建一个字符串到整数的映射。遍历列表以将字符串添加到地图中。如果 String 已经存在,则将 Integer 加 1。否则,将 String 和 1 添加到地图中。
  • 如果您想将日期存储在一行中,您只需将日期与某种分隔符并排放置,例如date : date : datedate | date | date。但是,如果您已经将日期放在单独的行上,则没有必要,因为每行已经充当分隔符。你只需要修改你的内部循环逻辑来解决它。

标签: java arrays list count frequency


【解决方案1】:

问题

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

解决办法

将流和分析代码移出 for 循环。

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

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

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

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

【讨论】:

    【解决方案2】:

    根据我认为这是如何工作的,我将按以下方式进行。包括注释以解释其他逻辑。主要思想是在你的主循环中尽可能多地做。使用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 列表并希望保留您的结构,因此我没有使用该功能。

    【讨论】:

      【解决方案3】:

      我对此进行了简单的测试,您可以查看结果

      {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();
              }
      

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2018-03-23
          • 2021-07-28
          • 1970-01-01
          • 1970-01-01
          • 2015-02-05
          • 2014-03-01
          • 2019-09-12
          • 2017-09-14
          相关资源
          最近更新 更多