2

So I got a treemap to which I add courses that come from a random generator, the names are consistent but the order is not. For example I got these:

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");

Now that's ten courses in total, and while the code below works to count one of them it would mean i have to get about nine more int variables written and repeat the if statement another nine times, that would be undesirable. I should mention the treemap is inside a loop and resets everytime, which is something I want. but a second treemap can be made outside the loop to add the courses, i got no issue with that. But it is entirely possible that some courses never even gets added to the treemap as they are randomly chosen from the ten above.

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 is a int array of size 3. Where a random number is stored, it is then used to choose from courses list a position which corresponds to a course.

  • May not be the most efficient, but I'd make a for loop over the list, and collect the counts in HashMap – MightyPork Oct 28 '15 at 17:59
  • 3
    What are you even trying to achieve with that `TreeMap`? It doesn't make any sense. Are you trying to see whether `order[0]`, `order[1]`, and `order[2]` are all `"HAL9000"`? The TreeMap isn't helping you do that in any way whatsoever. Also, `==` isn't how you check string equality; you do that with `equals`. – user2357112 Oct 28 '15 at 18:02
  • @user2357112 why equals? – Pursuer of Dying Stars Oct 28 '15 at 18:05
  • 1
    Because `==` tests for reference equality and `equals()` tests for object equailty. – Kayaman Oct 28 '15 at 18:07
  • Your question is unclear. Please explain exactly what part of this story is the input, and what you are trying to do with that input. What's in `order`? What is `courses` and where are you using `course`? What's the loop they are inside? – RealSkeptic Oct 28 '15 at 18:13
  • @RealSkeptic Done, I edited to show more and explain. The input is the list of courses and selected based on a random number from 1 to 10. – Pursuer of Dying Stars Oct 28 '15 at 18:20
  • 1. indent your code kthxbai, 2. variable names should start with lowercase letters (`NumberOfStudents`, `HAL9000students`, `SortedCourses`), 3. why do you assign the `courses.get(order[0]).toString()` things to a variable *after* already using them as treemap keys? and why do you call them comparators? they are no comparators, friend, and naming is important -- it's one of the two hardest things in computer science, 4. why do you use iterator? just do `for (Map.Entry entry : tmap.entrySet())` – Michal M Oct 28 '15 at 18:59
  • Anyways, a tree map is not like the best available option for counting things. You may want to take a look at *bags* from commons-collections. Although I am not sure. Please refactor your code a bit (e.g. according to my previous comment) because right now it looks obfuscated. – Michal M Oct 28 '15 at 19:01

1 Answers1

1

Whenever you have a situation where you need to do the same sort of operation for a lot of different values, it should give you a hint not to use individual variables, but rather an array or a collection.

You want to get the number of students in each course. So instead of keeping a variable for every course (what happens if there are 15 courses? 100?), you can use a map from the course name to the number of students in that course.

In this case, since you are already dealing with the indexes of the courses rather than their name, you can actually do that with an array.

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

This will be, of course, declared outside the loop. In this array, studentCounts[0] will be the number of students in the course indexed 0 ("COP2210"). studentCounts[1] will be the number of students in course index 1 ("COP2250") and so on.

So, if your order array is, for example, {3,5,9}, then you'll need to increment studentCounts[3], studentCount[5] and studentCount[9]:

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

Your second issue is that you want to print the names of the courses selected for each student ordered alphabetically. You use a TreeMap for that, but there is no reason to use a map - you are not actually using the values of the map, just the keys. So a TreeSet is going to make more sense.

So if you declare

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

You can add to it inside the loop above:

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

A Set has a simpler iterator than a Map. You can get the strings directly:

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

So, some notes:

  • Java has coding conventions. Type names (class,interface,enum) should start with a capital letter (e.g. BigPicture). Method, variable and field names should start with a lowercase letter (e.g. bigPicture), and constants should be all-caps (e.g. BIG_PICTURE). So a variable name like SortedCourses is bad, and so is HAL9000students and ID_prefix. I assumed that the ID prefix is a constant (declared static final String), so ID_PREFIX is the correct name. But if it's a variable, it should be idPrefix.
  • Do not use raw types. Never declare anything to be a List, TreeMap, etc., without using the base type. It has to be List<String>, TreeMap<String,Integer>, Set<Map.Entry<String,Integer>> and so on. Using generics properly is important for type safety, and it saves you casting. So don't ignore those warnings about "raw types" that the compiler gives you!
  • In my solution, you don't need to compare strings. But if you need to compare strings, you do it by str1.equals(str2), not str1 == str2.
  • Don't use the operator + to concatenate strings in loops. It's good enough for something like a = "foo " + b + "bar" - a single string concatenation. But in a loop:

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

    Too many objects are created and discarded. It's better to use a StringBuilder as I have shown.

RealSkeptic
  • 33,993
  • 7
  • 53
  • 79