有没有更有效的方法来计算带有树图的字符串实例?
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
这样的变量名是不好的,HAL9000students
和 ID_prefix
也是。我假定 ID 前缀是一个常量(声明为 static final String
),因此 ID_PREFIX
是正确的名称。但是如果是变量的话,应该是idPrefix
.
- 不要不要使用原始类型。切勿在不使用基类型的情况下将任何内容声明为
List
、TreeMap
等。它必须是 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
。
所以我得到了一个树状图,我向其中添加了来自随机生成器的课程,名称一致但顺序不同。例如我得到了这些:
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
这样的变量名是不好的,HAL9000students
和ID_prefix
也是。我假定 ID 前缀是一个常量(声明为static final String
),因此ID_PREFIX
是正确的名称。但是如果是变量的话,应该是idPrefix
. - 不要不要使用原始类型。切勿在不使用基类型的情况下将任何内容声明为
List
、TreeMap
等。它必须是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
。