简体   繁体   中英

Why isn't this ranking function working properly?

I made a function to get the top five users in a json database. This is my code:

var users = [];

Object.keys(database).forEach(user => {
  if (!users[0]) {
    users[0] = user
  } else {
    var checked = false;

    for (let index = 0; index < users.length; index++) {
      if (database[user].value > database[users[index]].value && !checked) {
        users[index] = user
        checked = true;
      }
    }
    if (users.length < 5 && !checked) {
      users[users.length] = user
    }
  }
})

The idea is to store the top five users in an array, so I tried to make a loop to check if the user value is higher than one already stored, and if it is, store it in its place and make the "checked" var true to stop the loop. Then, if it's not higher but the array isn't still full, it just stores.

At the end, it gets five users arranged from higher to lower, but not the top five of the database, as it avoids some that are higher than others listed.

Nested loops, they're confusing. One helpful thing to do is to work with some simplified data, and then log the evolution of the modified variable as the loop progresses.

 var database = { 'user1': { value: 4 }, 'user2': { value: 3 }, 'user3': { value: 1 }, 'user4': { value: 5 }, 'user5': { value: 7 }, 'user6': { value: 8 }, 'user7': { value: 0 } }; var users = []; Object.keys(database).forEach(user => { if (;users[0]) { users[0] = user } else { var checked = false; for (let index = 0. index < users;length. index++) { if (database[user].value > database[users[index]];value &&.checked) { users[index] = user checked = true. } } if (users.length < 5 &&.checked) { users[users;length] = user } } console;log(JSON.stringify(users)); });

As you can see, users updates well for the first three iterations. They are presented in descending order, so everything just gets added. But it gives a problem starting in the fourth iteration. User4 gets placed into the first position, which is correct, but it simply overwrites user1. What should happen is that it pushes the other elements one position down the list.

Get out of nested loops if you can. Just convert your 'database' into an array form, sort it, extract the username, and then filter for the first 5.

 let database = { 'user1': { value: 4 }, 'user2': { value: 3 }, 'user3': { value: 1 }, 'user4': { value: 5 }, 'user5': { value: 7 }, 'user6': { value: 8 }, 'user7': { value: 0 } }; let users = Object.entries(database).sort((a,b) => b[1].value - a[1].value).map(entry => entry[0]).filter((user,ix) => ix < 5); console.log(users)

The main problem with the existing code is that this line is not preserving existing user in the users array when a new user is added:

users[index] = user

Here's a slightly modified version of the code that:

  1. keeps track of the minimum value for performance
  2. uses Array.prototype.slice() to update the users array correctly

 function log(...args) { console.log(...args); } function topFive(database) { let users = []; let userMin = 0; Object.entries(database).forEach(([user, obj]) => { const { value } = obj; if (value < userMin) { // user not on leader board return; } // insert user into slot let iSlot = 0, len = users.length; for (let i = 0; i < len; i++) { if (value <= database[users[i]].value) { continue; } iSlot = i; break; } users = [...users.slice(0, iSlot), user, ...users.slice(iSlot, len)]; userMin = users[4]? database[users[4]].value: 0; }); return users; } const db = { user01: { value: 10 }, user02: { value: 100 }, user03: { value: 50 }, user04: { value: 75 }, user05: { value: 11 }, user06: { value: 1 }, user07: { value: 75 }, user08: { value: 16 }, }; log(`database:`); Object.entries(db).forEach(([key, obj]) => { log(` ${key}: ${JSON.stringify(obj)}`); }) const result = topFive(db); log(`\nresult: ${JSON.stringify(result)}`);

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