【问题标题】:Adding <Key, Value> in hashmap by while loop but not working通过 while 循环在 hashmap 中添加 <Key, Value> 但不起作用
【发布时间】:2021-12-12 00:35:49
【问题描述】:

我有以下 CSV 文件,我想创建一个哈希图,其唯一键应该是每行的第一个值,值应该是 arraylist,其中包含该行第一个值下的每一行的信息. CSV 示例如下:

1,0
1,1
1,2
1,3
1,4
2,0
2,1
2,2
4,0
10,0
10,1
10,2
10,3
10,4
10,5

理想情况下,我希望最终的 ArrayList 类似于:

{1=[1,0, 1,1, 1,2, 1,3, 1,4], 2=[2,0, 2,1, 2,2], 4=[4,0], 10=[10,0, 10,1, 10,2, 10,3, 10,4, 10, 5]}

下面是我用来尝试通过while循环解决这个问题的代码

public static void main(String[] args) {
        int activityRecord = 1;
        String activitiesFile = "scenarios/BrusselsPopulationFromR/BrusselsActivities.csv";

        HashMap<Integer, ArrayList<String>> idAndAllActivities = new HashMap<>();
        try {
            BufferedReader activityReader = new BufferedReader(new FileReader(activitiesFile));
            String agentActivity = null;
            ArrayList activities = new ArrayList();

            while ((agentActivity = activityReader.readLine()) != null){
                String activityWithAllInfo = agentActivity;
                String[] activitySpilted = agentActivity.split(",");
                int activityAgentID = Integer.parseInt(activitySpilted[0]);

                if (activityAgentID == activityRecord){
                    activities.add(activityWithAllInfo);
                } else if (activityAgentID != activityRecord){
                    idAndAllActivities.put(activityRecord, activities);
                    activityRecord = activityAgentID;
                    activities.clear();
                    activities.add(activityWithAllInfo);
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println(idAndAllActivities);
    }

基本上,我会尝试证明activityAgentID == activityRecord是否(原本为1),如果不同,我会将添加到hashmap并清除activities arrayList。然而,这个程序的输出是这样的:

{1=[10,0, 10,1, 10,2, 10,3, 10,4, 10,5], 2=[10,0, 10,1, 10,2, 10,3, 10,4, 10,5], 4=[10,0, 10,1, 10,2, 10,3, 10,4, 10,5]}

这不是我想要的,我试图调试它,但我找不到原因,因为我对 Java 真的很陌生......我想知道你是否知道如何解决这个问题?任何提示将不胜感激!

谢谢!

【问题讨论】:

    标签: java arraylist hashmap


    【解决方案1】:

    您的代码中的问题是您重用了activities 数组。活动数组和HashMap 中分配的数组都指向同一个引用,所以如果你更新activities 数组,地图中的所有条目也会更新。

    假设文件有排序的键,你可以像这样调整你的代码

    HashMap<Integer, ArrayList<String>> idAndAllActivities = new HashMap<>();
    try {
        BufferedReader activityReader = new BufferedReader(new FileReader(activitiesFile));
        String agentActivity = null;
        ArrayList<String> activities = new ArrayList<>();
    
        while ((agentActivity = activityReader.readLine()) != null){
              String[] activitySpilted = agentActivity.split(",");
              int activityAgentID = Integer.parseInt(activitySpilted[0]);
    
              if (activityAgentID == activityRecord){
                   activities.add(agentActivity);
              } else {
                   idAndAllActivities.put(activityRecord, activities);
                   activityRecord = activityAgentID;
                   activities = new ArrayList<>();
                   activities.add(agentActivity);
              }
         }
    
         idAndAllActivities.put(activityRecord, activities);
    
    } catch (IOException e) {
            e.printStackTrace();
    }
    
    System.out.println(idAndAllActivities);
    

    请注意,您不需要这个:String activityWithAllInfo = agentActivity;,因为String 在 Java 中是不可变的

    【讨论】:

      【解决方案2】:

      你可以用另一种方式来做。如果CSV文件的顺序发生如下变化也不会中断的方式:

      1,0
      1,1
      2,0
      1,2
      10,0
      10,1
      10,2
      1,3
      1,4
      2,1
      2,2
      4,0
      10,3
      10,4
      10,5
      

      使用此 CSV,您的代码将失败,因为您依赖 CSV 文件将所有 1 活动记录放在一起。为了解决这个问题,请尝试以下操作(注意您不再依赖activityRecord):

      public static void main(String[] args) {
          String activitiesFile = "scenarios/BrusselsPopulationFromR/BrusselsActivities.csv";
      
          HashMap<Integer, ArrayList<String>> idAndAllActivities = new HashMap<>();
          try {
              BufferedReader activityReader = new BufferedReader(new FileReader(activitiesFile));
              String agentActivity = null;
      
              while ((agentActivity = activityReader.readLine()) != null){
                  String activityWithAllInfo = agentActivity;
                  String[] activitySpilted = agentActivity.split(",");
                  int activityAgentID = Integer.parseInt(activitySpilted[0]);
      
                  if (idAndAllActivities.containsKey(activityAgentID)){
                      ArrayList existentActivities = idAndAllActivities.get(activityAgentID);
                      existentActivities.add(activityWithAllInfo);
                  } else {
                      ArrayList activities = new ArrayList();
                      activities.add(activityWithAllInfo);
                      idAndAllActivities.put(activityAgentID, activities);
                  }
              }
      
          } catch (IOException e) {
              e.printStackTrace();
          }
      
          System.out.println(idAndAllActivities);
      }
      

      【讨论】:

      • 您好 João,感谢您的回答。虽然您的代码运行良好,但我仍然想知道为什么在使用 existentActivities.add(activityWithAllInfo) 时,新值将添加到对应于键 activityAgentID 的原始 hashmap 值中?在我的理解中,您只是更改了arrayList existentActivities,而不是Hashmap 中的原始arrayList?谢谢:)
      • 嗨@Jingjun,不,事实并非如此。默认情况下,Java 集合是可变的,这意味着当我们执行 ArrayList existentActivities = idAndAllActivities.get(activityAgentID); 时,我们实际上在 HashMap 中引用了实际列表,我们可以将其更改(在您的情况下更新)以增加一个元素。这实际上是您的实施的问题。您总是在更改相同的ArrayList,因此您最终得到了输出;)
      • 非常感谢@João Dias,这很清楚 :) 我的问题已经完美解决了!
      • @Jingjun,有什么理由改变接受的答案吗?我的回答是否有任何问题无法以任何方式解决您的问题?
      • 只是误击 :) 现已修复,抱歉@João Dias
      【解决方案3】:

      假设您使用的是 Java 8 或更高版本,在 Files.linesCollectors.groupingBy 的帮助下,任务可以大大简化并且代码更具可读性:

      import java.io.IOException;
      import java.nio.file.Files;
      import java.nio.file.Paths;
      import java.util.List;
      import java.util.Map;
      import java.util.stream.Collectors;
      import java.util.stream.Stream;
      
      public class Example {
      
          public static void main(String[] args) {
              String activitiesFile = "scenarios/BrusselsPopulationFromR/BrusselsActivities.csv";
              Map<Integer,List<String>> idAndAllActivities = null;
              try (Stream<String> content = Files.lines(Paths.get(activitiesFile))) {
                  idAndAllActivities = content.collect(Collectors.groupingBy(row -> Integer.parseInt(row.split(",")[0])));
              } catch (IOException e) {
                  e.printStackTrace();
              }
              System.out.println(idAndAllActivities);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-10-19
        相关资源
        最近更新 更多