有没有更有效的方法来计算带有树图的字符串实例?

Is there a more efficient way of counting instances of a string with treemaps?

所以我得到了一个树状图,我向其中添加了来自随机生成器的课程,名称一致但顺序不同。例如我得到了这些:

List course = new ArrayList();             
        course.add("COP2210");
        course.add("COP2250");
        course.add("ENC1250");
        course.add("MLP1337");
        course.add("ENC3250");
        course.add("REL2210");
        course.add("MUS3200");
        course.add("PHI1240");
        course.add("SOL5000");
        course.add("HAL9000");

现在总共有十门课程,虽然下面的代码可以算出其中一门,但这意味着我必须再编写大约九个 int 变量并再重复 if 语句九次,这是不希望的。我应该提到树状图在一个循环中并且每次都会重置,这是我想要的。但是可以在循环外制作第二个树图来添加课程,我对此没有意见。但是完全有可能有些课程甚至从来没有被添加到树状图中,因为它们是从上面的十个中随机选择的。

for (int i = 0; i < NumberOfStudents; ++i){

        order = RandomCourse();

        TreeMap<String, Integer> tmap = new TreeMap<String, Integer>();
        tmap.put(courses.get(order[0]).toString(), 0);
        tmap.put(courses.get(order[1]).toString(), 0);
        tmap.put(courses.get(order[2]).toString(), 0);


        String comparator1 = courses.get(order[0]).toString();
        String comparator2 = courses.get(order[1]).toString();
        String comparator3 = courses.get(order[2]).toString();

        if(comparator1 == "HAL9000" || comparator2 == "HAL9000" || comparator3 == "HAL9000")
        HAL9000students++;




        courses.indexOf(order[0]);

        //Clean variable
        SortedCourses = "";

        //Map logic
        Set set = tmap.entrySet();
        Iterator iterator = set.iterator();
        while(iterator.hasNext()) {
         Map.Entry mentry = (Map.Entry)iterator.next();
        SortedCourses = SortedCourses + mentry.getKey() + " ";

      }

        students.add(ID_Prefix + i+ ", " + student.get(i) + " " + SortedCourses);
                                                  }

Order 是一个大小为 3 的 int 数组。其中存储了一个随机数,然后用于从课程列表中选择与课程对应的位置。

每当您需要对很多不同的值执行相同类型的操作时,它应该提示您不要使用单个变量,而应该使用数组或集合。

您想获得每门课程的学生人数。因此,与其为每门课程保留一个变量(如果有 15 门课程会怎样?100 门?),您可以使用从课程名称到该课程学生人数的映射。

在这种情况下,由于您已经在处理课程的 索引 而不是它们的名称,您实际上可以使用数组来实现。

int[] studentCounts = new int[course.size()];

当然,这将在循环外声明。在此数组中,studentCounts[0] 将是课程中索引为 0 ("COP2210") 的学生人数。 studentCounts[1] 将是课程索引 1 ("COP2250") 中的学生人数,依此类推。

因此,如果您的 order 数组是 {3,5,9},那么您需要递增 studentCounts[3]studentCount[5]studentCount[9] :

for ( int courseIndex : order ) {
    studentCounts[courseIndex]++;
}

您的第二个问题是您想要打印为每个学生选择的课程名称,并按字母顺序排列。您为此使用 TreeMap ,但没有理由使用地图 - 您实际上并没有使用地图的值,只是键。所以 TreeSet 会更有意义。

所以如果你声明

TreeSet<String> sortedCourseNames = new TreeSet<>();

您可以在上面的循环中添加:

for ( int courseIndex : order ) {
    studentCounts[courseIndex]++;
    sortedCourseNames.add( course.get(courseIndex) );
}

A Set 有一个比 Map 更简单的迭代器。可以直接获取字符串:

StringBuilder sb = new StringBuilder();
sb.append(ID_PREFIX)
  .append(i)
  .append(',')
  .append(student.get(i))
  .append(' ');

for ( String courseName : sortedCourseNames ) {
    sb.append(courseName)
      .append(' ');
}

students.add( sb.toString() );

所以,一些注意事项:

  • Java 有编码约定。类型名称(class、接口、枚举)应以大写字母开头(例如 BigPicture)。方法、变量和字段名称应以小写字母开头(例如 bigPicture),常量应全部大写(例如 BIG_PICTURE)。所以像 SortedCourses 这样的变量名是不好的,HAL9000studentsID_prefix 也是。我假定 ID 前缀是一个常量(声明为 static final String),因此 ID_PREFIX 是正确的名称。但是如果是变量的话,应该是idPrefix.
  • 不要不要使用原始类型。切勿在不使用基类型的情况下将任何内容声明为 ListTreeMap 等。它必须是 List<String>TreeMap<String,Integer>Set<Map.Entry<String,Integer>> 等等。正确使用泛型对于类型安全很重要,它可以节省转换时间。所以不要忽略编译器给你的那些关于 "raw types" 的警告!
  • 在我的解决方案中,您不需要比较字符串。但是如果你需要比较字符串,你可以通过 str1.equals(str2) 而不是 str1 == str2.
  • 不要使用运算符 + 来连接循环中的字符串。对于像 a = "foo " + b + "bar" 这样的东西来说已经足够了——一个单一的字符串连接。但是在一个循环中:

    String result = "";
    for (i = 1; i < 5; i++) {
        result = result + " something else ";
    }
    

    创建和丢弃的对象太多。如我所示,最好使用 StringBuilder