Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

JavaScript JavaScript Loops, Arrays and Objects Tracking Data Using Objects The Student Record Search Challenge Solution

Antonija Kasum
Antonija Kasum
4,918 Points

Does anyone know the solution for when you have two students with the same name?

I have no idea how to solve that. Any idea? My code is below

var students = [
    { 
      name: "Ana", 
      track: "iOS",
      achievements: 2,
      points: 100
    },
    { 
      name: "Iva", 
      track: "Web Design",
      achievements: 6,
      points: 150
    },
    { 
      name: "Una", 
      track: "Front end",
      achievements: 1,
      points: 200
    },
    { 
      name: "ana", 
      track: "JS",
      achievements: 10,
      points: 500
    },
    { 
      name: "Ina", 
      track: "HTML/CSS",
      achievements: 3,
      points: 103
    },
];

var student;
var exit = "QUIT";


while (true){
    var search = prompt("Search student records. Type a name or type 'quit' to end.");

    if (search === exit || search === null){
        break;
    }
    for (var i = 0; i < students.length; i += 1){
        if (search.toUpperCase() === students[i].name.toUpperCase()){
            student = "<h2>  Student: " + students[i].name + "</h2>";
            student += "<p> Track: " + students[i].track + "</p>";
            student += "<p> Achievements: " + students[i].achievements + "</p>";
            student += "<p> Points: " + students[i].points+ "</p>";
            document.write(student);

        } else {
            document.write("Sorry no one under that name!");
            break;
        }
    }
}

6 Answers

This is my first post. It is one of many possible solutions to your question. This solution uses the indexOf() method which returns the position of the first occurrence of the search value if it is found OR -1 if the search value is not found. This allows the user to search for parts of a name in addition to entire matches. For example, say the list of students included the names: Andrea, Jacob, Andy, and Joe. The user could search for 'An' and both Andrea and Andy would appear in the results list since they both contain the substring 'An'. If you're uncomfortable with this, using the straightforward === operator still works too.

The portion that you're interested in, though, involves concatenating student info to a string which will be printed out later. The instructor used message = getStudentReport( student ) in his solution. You used document.write(student) in yours. The issue with doing this is it overwrites information from previously found student(s) with info from the last student found. The solution below uses html += getStudentInfo(student) to add onto the string, rather than overwrite it.

Note: I read a snippet on w3schools about how using document.write() after an HTML document is fully loaded can delete all existing HTML. So be careful with that.

var search;     // Stores student (string) user is searching for
var student;    // Stores student object

// Grab property info for given student
function getStudentInfo(student) {
  var info = '';
  // Aggregates all the data for this student
  for(var property in student) {
      info += '<p><strong>' + property + ':</strong> ' + student[property] + '</p>';
  }
  return info;
}

// Display message to output div
function print(message) {
  var outputDiv = document.getElementById('output');
  outputDiv.innerHTML = message;
  return;
}

// Continue asking user for input until they enter quit or click cancel
while(true) {
  // Get a name to search for from user OR 'quit'
  search = prompt('Search student records: type a name[Earle] (or type "quit" to end)');

  // If the user clicks cancel or enters 'quit', end
  if(search === null || search.toLowerCase() === "quit") {
    break;
  }

  // Otherwise, find student(s)!
  var studentFound = false; // Indicates if student with name matching search found
  var html = '';

  // Go through all students and aggregate info for students that match search
  for(var i = 0; i < students.length; i++) {
    student = students[i];
    // Grab student info if student's name includes search string
    if((student.name.toLowerCase()).indexOf(search.toLowerCase()) > -1) {
      html += getStudentInfo(student);
      studentFound = true;
    }
  }

  // If at least one student found, print out student info, otherwise indicate not found
  if(studentFound) {
    print(html);
  }
  else {
    print("Student " + search.toUpperCase() + " not found");
  }
}

Happy coding!

Edit (03/25/2016): Turns out, document.write() in Antonija's solution is not overwriting previously found student info like the instructor's solution does. The code is not exhibiting the erase-all issue that document.write() sometimes does. The if-else in the for loop is the culprit. If a student does not match the search string, it breaks out of the loop so no other students are checked. If you had three students named 'Ana' at the beginning followed by 'Iva' and then searched for 'Ana', all three would print out. It'd stop as soon as a non-matching name was reached :P.

Antonija Kasum
Antonija Kasum
4,918 Points

hm this sounds about right but my code gives me only first result, not only last result. I guess I have additional error in my code :/

I was using document.write() out of lazyness, I know it's not a good practice. I'm a bit impatient when coding I think that's the problem :) Your code and explanation are great, thank you! Now I'm inspired to do it all better :)

Excellent points. Let's examine your code a bit closer to understand its execution and output better. You use a for loop to iterate through all the students. You use the conditional check if (search.toUpperCase() === students[i].name.toUpperCase()) to see if a given student's name matches the search string, normalizing the casing so the casing the user enters does not matter (nice touch!). But you also include an else block which executes every time this condition is not true. This is where the issue lies. Keep in mind that since this if statement is included in the for loop, it executes each iteration. This means for each student, you are checking to see if their name matches the search string. If it doesn't, the else will execute which means "Sorry no one under that name" will print and you will break out of the loop -- no longer checking any of the students (even if there are others that match!).

If we look at your student data, we can see the names here (I'm including just the names for simplification, not the entire object): ['Ana', 'Iva', 'Una', 'ana', 'Ina']. Cute names haha. Say user input is "Ana." For the first iteration of your loop, the program will check to see if the element at the first index in your array (index 0) is equal to user input. It is. Ana's info will be written to the screen. On the next iteration, though, the element is "Iva" and that does not match user input "Ana". Since the condition in the if is not true (it is false), the else executes. "Sorry no one under that name" is printed out and you break out of the loop - the other "ana" is never checked/reached! So that data is never printed. You might not have even noticed "Sorry no one under that name" was printed out after Ana's info.

Using your solution as a template, the code below may be closer to what you want. Keep in mind that we only know if the student does not exist after going through the entire list (after the for loop is done). You'll notice that using document.write() in this way appends to what is already written. So each time you search for a student, rather than erasing the previous results and showing only the results of the most recent search, it keeps adding onto the HTML document (showing previous results and new results, making the output pretty long after multiple tries).

var student;
var exit = "QUIT";

while (true){
  var search = prompt("Search student records. Type a name or type 'quit' to end.");

  if (search === exit || search === null){
    break;
  }

  // Stores whether student was found (true = student found, false = not found)
  var found = false;

  for (var i = 0; i < students.length; i += 1){
    if (search.toUpperCase() === students[i].name.toUpperCase()){
      student = "<h2>  Student: " + students[i].name + "</h2>";
      student += "<p> Track: " + students[i].track + "</p>";
      student += "<p> Achievements: " + students[i].achievements + "</p>";
      student += "<p> Points: " + students[i].points+ "</p>";
      found = true;
      document.write(student);
    }
  }

  // We only know if the student was not found after going through the entire list
  if(!found) {
    document.write("Sorry no one under that name!");
  }
}

Hope this helps!

Antonija Kasum
Antonija Kasum
4,918 Points

Oh it helps a lot! I understand it perfectly now! Thank you!

Typically, in a database connecting solution, there would be a unique ID attached to each record to avoid collisions against this.

In this case, though, you are pretty limited in the possibilities of uniqueness, unless you added a sequential identifier. For example:

//...
{ 
      id: 1,
      name: "Ana", 
      track: "iOS",
      achievements: 2,
      points: 100
    } 
//...

Another option would be to compare the records based upon their capitalization, but I personally don't believe that's a very good solution.

var students = [ {name:'a', track: 'b', acheivements: 'c', points: 120 }, {name: 'd', track: 'e', acheivements: 'f', points: 121 }, {name: 'a', track: 'h', acheivements: 'j', points: 122 }, {name: 'l', track: 'q', acheivements: 'w' , points: 124 }, {name: 'o', track: 'u', acheivements: 'y' , points: '125' } ]

var html;
var input

    do {
    input = prompt('Who are you looking for?')
    for (var i =0; i<students.length; i++)
    if (input=== students[i].name){
        html += '<ul>';
        html += '<li> Students:' + students[i].name + '</li>';
        html += '<li> Track:' + students[i].track + '</li>';
        html += '<li> Acheivments:' + students[i].acheivments + '</li>';
        html += '<li> Points' + students[i].points + '</li>' ;
        html += '</ul>';
    }

} while (input !== 'quit');


document.write(html);
html = ' ';
Heather Li
Heather Li
6,124 Points

Just have a try :)

var search;
var searchResult = ' ';

var students = [
  {
   name:'Alice',
   track:'PHP',
   achievements:1,
   points:10
  },
  {
  name:'David',
  track:'Java',
  achievements:2,
  points:true
  },
  {
  name:'Ella',
  track:'Ruby',
  achievements:3,
  points:30
  },
  {
  name:'Grace',
  track:'HTML',
  achievements:4,
  points:40
  },
  {
  name:'Helen',
  track:'Python',
  achievements:5,
  points:50
  },
  {
  name:'Lily',
  track:'CSS',
  achievements:6,
  points:60
  },
  {
   name:'Alice',
   track:'C++',
   achievements:7,
   points:70
  }
]

function print(message) {
  var outputDiv = document.getElementById('output');
  outputDiv.innerHTML = message;
}

do {
  search = prompt("Please enter a student's name or quit to quit:");
  for (var i = 0;i<students.length;i+=1) {
    if (search.toLowerCase() === students[i].name.toLowerCase()) {
      for (pro in students[i]) {
        searchResult += (pro+': '+students[i][pro]+'</br>');
        print(searchResult);
      }
    }
  }
} while(search.toLowerCase() !== 'quit' || search.toLowerCase() !==null );
Alexei Parphyonov
Alexei Parphyonov
34,128 Points

I got it working, but faced a few more problems with compatibility since most of my functions had different parameters (i.e. objects, array or array indices positions). Here is the code:

function ifMany(studentName) {
    // all students
    const given = students;
    // student name
    const name = studentName;
    // array for those names which are not once met in the students array of objects
    let indices = [];
    // for-loop 1, through all students
    for (let i = 0; i < given.length; i += 1) {
        // for-loop 2, through all students
        for (let j = 0; j < given.length; j += 1) {
            // the condition is that function argument is equal to a name in the students array but at the same time is not equal to itself.
            if (given[i].name === name && given[i].name !== given[j].name) {
                let index = i;
                // assume there are three students with the same name, if it were not for the second part of the conditional, the array will have 3 * array.length indexes.
                indices.push(index);
                break;
            }
        }
    }
    return indices;
}

After that in the function I called 'searchByName', I checked if there more than one student under this or that name and ran another for loop for the number of times the name is repeated, the same number of times another function 'getRecord' accessed each student by index and published info in the web-browser.