【问题标题】:Collection list is returning duplicates收藏列表返回重复项
【发布时间】:2018-03-14 03:40:10
【问题描述】:

嘿,我正在实现这个功能。

private static HashMap<String, Set<String>> enrollments = new HashMap<String, Set<String>>();
private static Set<String> studentset;
/**
 * Enrolls a student into a unit.
 * 
 * @param unit
 * @param student
 */
public static void enroll(String unit, String student) {

    if(!enrollments.containsKey(unit)) {
        studentset = new HashSet<String>();
    }
    studentset.add(student);
    enrollments.put(unit, studentset);

}


/**
     * Gets a list of all students of a particular discipline. E.g. If discipline is
     * "ABC" then return a collection of all students enrolled in units that start
     * with "ABC", so ABC301, ABC299, ABC741 etc. This method is non-trivial so it
     * would help to first implement the helper method matchesDiscipline (below).
     * 
     * @param discipline
     * @return
     */

    public static Set<String> getStudents(String discipline) {

        Set<String> myList = new HashSet<String>();

        for (Entry<String, Set<String>> e : enrollments.entrySet()) {
            if (e.getKey().startsWith(discipline)) {

                myList.addAll(e.getValue());

            }
        }

        return myList;
    }

public static void main(String[] args) {
        EnrollmentManager.enroll("CAB302", "James");
        EnrollmentManager.enroll("CAB403", "Ben");
        EnrollmentManager.enroll("CAB302", "James");
        EnrollmentManager.enroll("CAB403", "Morgan");
        EnrollmentManager.enroll("CAB404", "Sam");
        System.out.println(EnrollmentManager.getStudents("CAB3"));
    }

我遇到的问题是“myList”正在输出 [Morgan, James, Ben]。正确答案是[詹姆斯]。我哪里错了?抱歉,如果它是 Collections 新手的简单解决方案。

【问题讨论】:

  • 你能粘贴你的enroll函数吗?
  • 另外,预期的输出不应该是 James 吗?因为e.getKey().startsWith(discipline) 将匹配您的输入“CAB3”,根据您的数据,似乎只有 James 匹配它。
  • 我已经更新了帖子
  • IMO 如果地图是 &lt;Student, List&lt;Units&gt;&gt; 会更有意义
  • @Sam 你的问题解决了吗?

标签: java list collections set


【解决方案1】:

您的代码的问题在于您使用的是静态studentSet 变量。让我试运行你的代码。

您在这里所做的是在找不到密钥时创建一个新集合,否则您正在使用现有集合,这是您的静态成员。

if(!enrollments.containsKey(unit)) { 
    studentset = new HashSet<String>();
}

EnrollmentManager.enroll("CAB302", "James"); 将创建一个新集合,比如说 set1 并将其分配给静态成员 studentset。学生在这一步 {James} 之后设置。

EnrollmentManager.enroll("CAB403", "Ben"); 将创建一个新集合,比如说 set2 并将其分配给静态成员 studentset。这一步之后的学生设置{Ben}

EnrollmentManager.enroll("CAB302", "James");创建一个新集合并使用 studentset 的当前值,即 set2。学生在这一步之后设置 {Ben,James}

EnrollmentManager.enroll("CAB403", "Morgan");创建一个新集合并使用 studentset 的当前值,即 set2。学生在这一步 {Ben,James,Morgan} 之后设置。 而且由于您的地图引用了该静态成员,因此无论何时检索,您都会获得静态成员值..

您应该做的不是使用静态集合成员,而是使用函数变量。 并像这样改变你的条件:

Hashset<String> studentset = null;
if(!enrollments.containsKey(unit)) { 
    studentset = new HashSet<String>();
}else{
   studentset = enrollments.containsKey(unit);
}

【讨论】:

    【解决方案2】:

    问题出在您的静态变量 studentset 上,即使 unit 的映射中已经存在 studentset,您也正在添加到该集合中。如果找到键,您应该添加到地图中已经存在的集合中。

    如果您使用的是 Java 8 或更高版本,您只需一行即可完成:

    enrollments.computeIfAbsent(unit, k -> new HashSet<>()).add(student);
    

    而且您根本不需要studentset 静态字段。

    【讨论】:

      【解决方案3】:

      您可以更改您的注册方法,如下所示:

      public static void enroll(String unit, String student) {
      
          if(!enrollments.containsKey(unit)) {
              studentset = new HashSet<String>();
              enrollments.put(unit, studentset);
          } else {
              studentset = enrollments.get(unit);
          }
          studentset.add(student);
      
      }
      

      您的错误:您有一个静态引用 private static Set&lt;String&gt; studentset;,在您的情况下,当 !enrollments.containsKey(unit) 返回 false 时,它​​用于在地图的上一个条目中添加一个新学生。最佳做法是将其设为局部变量并在注册方法中定义。

      【讨论】:

        猜你喜欢
        • 2015-10-04
        • 2014-04-11
        • 2012-11-30
        • 1970-01-01
        • 2020-07-22
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多