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
your approach seems very complicated. Why not use a built-in sorting capability, like this:
produces a ‘sorted’ variable with the contents:
does that meet your needs?
The issue is that you are generating random numbers that can be outside of the range you expect.
if
lo
=10 andhi
=30, when you do(Math.random() * hi)
you could sometimes get, for example,25
, which you would add tolo
and get35
, that is outside of the range.Fix it like this:
Noticed, you miss one or two things inside the partition function. here’s an edited copy of your code