skip to Main Content

For some reason my quick sort function implementation keeps adding undefined values in my object users_total_likes and as a result it gives me the following error when i compile and run it in the terminal (same goes with the browser):

 if(users[i][key] >= users[hi][key] && users[j][key] < users[hi][key]){
                                     ^

TypeError: Cannot read properties of undefined (reading 'likes')
    at partition (D:ProjectsClient Workmoodlearning-screen-testitem_e.js:71:38)
    at sort (D:ProjectsClient Workmoodlearning-screen-testitem_e.js:119:17)
    at sort (D:ProjectsClient Workmoodlearning-screen-testitem_e.js:125:9)
    at sort (D:ProjectsClient Workmoodlearning-screen-testitem_e.js:125:9)
    at Object.<anonymous> (D:ProjectsClient Workmoodlearning-screen-testitem_e.js:138:1)
    at Module._compile (node:internal/modules/cjs/loader:1103:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1157:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)

And when I do print out the object even when it has been strictly been defined explicitly, it outputs:

[
  { likes: 2, post: 'post 2' },
  { likes: 9, post: 'post 4' },
  { likes: 10, post: 'post 1' },
  { likes: 14, post: 'post 7' },
  { likes: 50, post: 'post 5' },
  { likes: 40, post: 'post 6' },
  undefined,
  <1 empty item>,
  { likes: 30, post: 'post 3' }
]
current hi: 6

at a certain iteration before it throws the TypeError

What I’m actually doing different here is just sorting my array of objects according to the ‘likes’ key, not through dot notation but by accessing the dictionary attributes through array notation. What might be the problem here?

Here is my full code:

let users_total_likes = [{
    likes: 10,
    post: 'post 1',
  },
  {
    likes: 2,
    post: 'post 2',
  },
  {
    likes: 30,
    post: 'post 3',
  },
  {
    likes: 9,
    post: 'post 4',
  },
  {
    likes: 50,
    post: 'post 5',
  },
  {
    likes: 40,
    post: 'post 6',
  },
  {
    likes: 14,
    post: 'post 7',
  },
];


const swap = (arr, i, j) => {
  /* 
  this is a utility funciton to swap elements in an array
  given the two elements indeces i and j

  args: 
      arr - array to swap the two elements in
      i - index of element 1
      j - index of element 2

  note: this modifies the array in place so no new copy array 
  of the array is returned
  */

  [arr[i], arr[j]] = [arr[j], arr[i]];
}

const partition = (users, lo, hi, key) => {
  // quick sort here
  let pivot = Math.floor((Math.random() * hi) + lo);
  swap(users, pivot, hi);

  let i = lo;

  // set j pionter to the last end of the scan
  let j = hi - 1;


  // console.log(`${users[i][key]} at index ${i}`);
  console.log(users);
  console.log(`current hi: ${hi} n`);

  // when i pointer has greater index it has crossed the 
  // border of the j pointer
  while (i <= j) {
    // if i and j ptrs are < and >= to pivot then increm and decrem
    if (users[i][key] >= users[hi][key] && users[j][key] < users[hi][key]) {
      swap(users, i, j);
      ++i;
    }

    // check if either of the two, needs to be incremented or decremented or both
    else if (users[i][key] >= users[hi][key] && users[j][key] >= users[hi][key]) {
      --j;
    } else if (users[j][key] < users[hi][key] && users[i][key] < users[hi][key]) {
      ++i;
    } else {
      --j;
      ++i;
    }
  }

  // swap pivot element located in [hi] and swap with i
  swap(users, i, hi);

  // return new position of fixed pivot element
  return i;
}

const sort = (users, lo, hi, key) => {
  /* 
  args:
      implements the quicksort sorting algorithm

      users - an iterable of objects containing the id and posts of users
      key - the key in which the sorting function should base from, or when
      the comparison happens between two values this is what is used

      lo -
      
      hi -

      key - key of the iterable of objects to use in comparing two values with

      note: this function modifies the array in place and does not return
      a new copy fo the array
  */

  // if lo is greater than hi, it means array length reached 1
  if (lo < hi) {
    fixed = partition(users, lo, hi, key);

    // processes the sorted left side of the pivot
    sort(users, lo, fixed - 1, key);

    // processes the sorted right side of the pivot
    sort(users, fixed + 1, hi, key);
  }
}

console.log(users_total_likes);
sort(users_total_likes, 0, users_total_likes.length - 1, 'likes');
console.log(users_total_likes);

UPDATE:

my code oddly works at certain times if I run the script in the terminal across those multiple times, and even then my code doesn’t sort the values correctly. What might explain this behavior?? Here is the output of my code:

[
  { likes: 10, post: 'post 1' },
  { likes: 2, post: 'post 2' },
  { likes: 30, post: 'post 3' },
  { likes: 9, post: 'post 4' },
  { likes: 50, post: 'post 5' },
  { likes: 40, post: 'post 6' },
  { likes: 14, post: 'post 7' }
]
[
  { likes: 2, post: 'post 2' },
  { likes: 9, post: 'post 4' },
  { likes: 10, post: 'post 1' },
  { likes: 14, post: 'post 7' },
  { likes: 30, post: 'post 3' },
  { likes: 50, post: 'post 5' },
  { likes: 40, post: 'post 6' }
]

3

Answers


  1. your approach seems very complicated. Why not use a built-in sorting capability, like this:

    let arr = [
       { likes: 10, post: 'post 1' },
       { likes: 2, post: 'post 2' },
       { likes: 30, post: 'post 3' },
       { likes: 9, post: 'post 4' },
       { likes: 50, post: 'post 5' },
       { likes: 40, post: 'post 6' },
       { likes: 14, post: 'post 7' }
     ]
    let sorted = arr.toSorted((a,b)=> b.likes - a.likes)
    

    produces a ‘sorted’ variable with the contents:

    [
      { likes: 2, post: 'post 2' },
      { likes: 9, post: 'post 4' },
      { likes: 10, post: 'post 1' },
      { likes: 14, post: 'post 7' },
      { likes: 30, post: 'post 3' },
      { likes: 40, post: 'post 6' },
      { likes: 50, post: 'post 5' }
    ]
    

    does that meet your needs?

    Login or Signup to reply.
  2. The issue is that you are generating random numbers that can be outside of the range you expect.

    const partition = (users, lo, hi, key) => {
      // quick sort here
      let pivot = Math.floor((Math.random() * hi) + lo);
      swap(users, pivot, hi);
      // ...
    

    if lo=10 and hi=30, when you do (Math.random() * hi) you could sometimes get, for example, 25, which you would add to lo and get 35, that is outside of the range.

    Fix it like this:

    const partition = (users, lo, hi, key) => {
      // quick sort here
      let pivot = Math.floor((Math.random() * (hi - lo)) + lo);
      swap(users, pivot, hi);
      // ...
    
    Login or Signup to reply.
  3. Noticed, you miss one or two things inside the partition function. here’s an edited copy of your code

    let users_total_likes = [{
        likes: 10,
        post: 'post 1',
      },
      {
        likes: 2,
        post: 'post 2',
      },
      {
        likes: 30,
        post: 'post 3',
      },
      {
        likes: 9,
        post: 'post 4',
      },
      {
        likes: 50,
        post: 'post 5',
      },
      {
        likes: 40,
        post: 'post 6',
      },
      {
        likes: 14,
        post: 'post 7',
      },
    ];
    
    
    const swap = (arr, i, j) => {
      /* 
      this is a utility funciton to swap elements in an array
      given the two elements indeces i and j
    
      args: 
          arr - array to swap the two elements in
          i - index of element 1
          j - index of element 2
    
      note: this modifies the array in place so no new copy array 
      of the array is returned
      */
    
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
    
    const partition = (users, lo, hi, key) => {
      // quick sort here
      let pivot = Math.floor((Math.random() * (hi - lo + 1)) + lo);
      swap(users, pivot, hi);
    
      let i = lo;
    
      // set j pionter to the last end of the scan
      let j = hi - 1;
    
    
      // console.log(`${users[i][key]} at index ${i}`);
      console.log(users);
      console.log(`current hi: ${hi} n`);
    
      // when i pointer has greater index it has crossed the 
      // border of the j pointer
      while (i <= j) {
        // if i and j ptrs are < and >= to pivot then increm and decrem
        if (users[i][key] >= users[hi][key] && users[j][key] < users[hi][key]) {
          swap(users, i, j);
          i++;
          j--;
        }
    
        // check if either of the two, needs to be incremented or decremented or both
        else if (users[i][key] >= users[hi][key]) {
          j--;
        } else if (users[j][key] < users[hi][key]) {
          i++;
        } else {
          j--;
          i++;
        }
      }
    
      // swap pivot element located in [hi] and swap with i
      swap(users, i, hi);
    
      // return new position of fixed pivot element
      return i;
    }
    
    const sort = (users, lo, hi, key) => {
      /* 
      args:
          implements the quicksort sorting algorithm
    
          users - an iterable of objects containing the id and posts of users
          key - the key in which the sorting function should base from, or when
          the comparison happens between two values this is what is used
    
          lo -
          
          hi -
    
          key - key of the iterable of objects to use in comparing two values with
    
          note: this function modifies the array in place and does not return
          a new copy fo the array
      */
    
      // if lo is greater than hi, it means array length reached 1
      if (lo < hi) {
        let fixed = partition(users, lo, hi, key);
    
        // processes the sorted left side of the pivot
        sort(users, lo, fixed - 1, key);
    
        // processes the sorted right side of the pivot
        sort(users, fixed + 1, hi, key);
      }
    }
    
    console.log(users_total_likes);
    sort(users_total_likes, 0, users_total_likes.length - 1, 'likes');
    console.log(users_total_likes);
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search