简体   繁体   中英

Javascript, using the reduce array method

So I'm doing the Odin Project. And one of the exercises is now hinting on using a reduce method. I am kind of stuck here and I've already looked at the solution. However I don't really know what kind of error I'm making if I do it on my own. The code that I've got is this:

let findTheOldest = function(people) {
    const oldestPerson = people.reduce((winner, person) => {
        if ((person.yearOfDeath - person.yearOfBirth) > (winner.yearOfDeath - winner.yearOfBirth)) {
            return person;
        } else if ((person.yearOfDeath - person.yearOfBirth) <= (winner.yearOfDeath - winner.yearOfBirth)) {
            return winner;
        }
    });
}

And the code they have is:

const findTheOldest = function(array) {
  return array.reduce((oldest, currentPerson) => {
    const oldestAge = getAge(oldest.yearOfBirth, oldest.yearOfDeath)
    const currentAge = getAge(currentPerson.yearOfBirth, currentPerson.yearOfDeath)
    return oldestAge < currentAge ? currentPerson : oldest
  })
}

const getAge = function(birth, death) {
  if (!death) {
    death = new Date().getFullYear();
  }
  return death - birth;
}

Now, I know if I look at it that their code is a lot more structured. But my own "solution" is the closest one I came to. And by now I'm trying to figure out what the difference is. I know that their code is eventually better. It's a lot more tidy, and using separate variables for storing the age is a lot cleaner and more clear. However both me and them return the "objects" in the same way. And for the first test case I should be able to pass, is what I'm thinking right now.

Maybe I must explain the test cases, the first one finds the oldest person based on calculating their age from yearBirth and yearDeath. And then the second test case should account for a person still being alive. And the third test case is that the alive person is in fact the oldest one so it should return that one. I'm only trying for the first one at the moment.

The error I'm getting is that "Cannot read property 'name' of undefined". I think that has got to do with the fact that the solution is trying to access the name property of the object I'm returning. Because this is their hint:

  • You should return the whole person object, but the tests mostly just check to make sure the name is correct.

There is a possibility that there is no yearOfDeath (if the person is not dead) in that case your code will retrieve undefined and undefined - yearOfBirth will give you NaN

Any comparison with NaN will be false hence you won't go in your if branch, neither in your else if branch. Therefore you won't return anything. If you replace the else if with a simple else you would return something but it would probably be a wrong result since the comparison is wrong.

That's why they made a function to retrieve the current year if there no yearOfDeath .

Also you need to return the oldestPerson variable at the end of your function.

In your code you can add something like (person.yearOfDeath || currentYear) :

 let findTheOldest = function(people) { const currentYear = new Date().getFullYear(); const oldestPerson = people.reduce((winner, person) => { if (((person.yearOfDeath || currentYear) - person.yearOfBirth) > ((winner.yearOfDeath || currentYear) - winner.yearOfBirth)) { return person; } else if (((person.yearOfDeath || currentYear) - person.yearOfBirth) <= ((winner.yearOfDeath || currentYear) - winner.yearOfBirth)) { return winner; } }); return oldestPerson; } const p1 = { yearOfBirth: 1990, yearOfDeath: 2015 } const p2 = { yearOfBirth: 1990 } // Edge case: calculate his age with current year console.log(findTheOldest([p1, p2]))

Now this code is quit difficult to read, that's why it's good to split it into separate functions.

A few things I noticed -

  • Use const (instead of let ) when we do not plan to reassign the variable
  • Use an initial value (second argument) to reduce to prevent program from blowing up when the data set is empty
  • Use of a compound result in reduce prevents us from recalculating the age of the oldest person in each iteration
  • Use of default values prevents null checks, unnecessary variable reassignments, and avoids running into NaN . Defaults also signal to programmer what type of data the function accepts

 const findTheOldest = (people = []) => people.reduce ( ([ oldest, oldestAge ], person) => { const age = getAge(person) // only compute age of current person return age > oldestAge? [ person, age ]: [ oldest, oldestAge ] }, [ undefined, -Infinity ] // initial value ) [0] // reduce returns [ <person>, <age> ], [0] gets the person out const getAge = ({ yearOfBirth = 0, yearOfDeath = 0 }) => yearOfDeath? yearOfDeath - yearOfBirth: (new Date).getFullYear() - yearOfBirth const peeps = [ { name: "Alice", yearOfBirth: 2000 }, { name: "Gertrude", yearOfBirth: 1910 }, { name: "Martha", yearOfBirth: 1900, yearOfDeath: 2006 }, { name: "Wanda", yearOfBirth: 1940 } ] // works as expected console.log(findTheOldest(peeps)) // { name: "Gertrude", ... } // works when data source is empty console.log(findTheOldest([])) // undefined // works when data is missing. console.log(findTheOldest()) // undefined

Try with this:

 let findTheOldest = function(people) { const oldestPerson = people.reduce((winner, person) => { if ((person.yearOfDeath - person.yearOfBirth) > (winner.yearOfDeath - winner.yearOfBirth)) { return person; } else if ((person.yearOfDeath - person.yearOfBirth) <= (winner.yearOfDeath - winner.yearOfBirth)) { return winner; } }); return oldestPerson; }

It is the same, but I just added return oldestPerson at the end of the function. Tell me if it works

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM