Array sorting is showing different results everytime - javascript

I might have close to 40 elements in the array. Ocasionally the array is sorted as I want it to be sorted but after I refresh the webpage, the order of sorting completely changes even if the information itself remains the same and the process of sorting is the same.
I notice that I get "2000 messages have not been logged" in the console, so I assume the logger gets overloaded.
Therefore, my first question is: do javascript executions have any 'timeout' as in a php script, for example?
And if not, what could be wrong with my code?
arr.sort(function (a, b) {
var a_freq = a["first"],
b_freq = b["first"],
a_imp = a["second"],
b_imp = b["second"],
a_ldone = a["third"],
b_ldone = b["third"];
var imp_diff = (a_imp - b_imp) / 10;
var relation;
if (imp_diff == 0){
if(b_ldone > a_ldone){
return 1;
}else if(b_ldone == a_ldone){
if(a_freq >= b_freq){
return 1;
}else{
return -1;
}
}else{
return -1;
}
}else if(imp_diff > 0){
if(b_ldone > imp_diff && a_ldone - b_ldone > imp_diff){
return 1;
}
return -1;
}else{
imp_diff = imp_diff * (-1);
if(a_ldone > imp_diff && b_ldone - a_ldone > imp_diff){
return -1;
}
return 1;
}
}
});
When I return 1, am I advancing element 'a' or 'b'?
As I said, the values stay the same with every refresh of the webpage but for some reason the order changes... Within every refresh, though, the value of the final array is saved in the cache, so the new array that is being sorted in a refresh is an array that has been sorted previously, but the values of each objet in the array stay the same... Any reason for it to change, sometimes so abruptly? Does the javascript process simply halt without completely finishing sorting the whole array? What would be the reason for this? As I wrote, I must have around 40/50 elements in the array... Is this too much to handle? Is there any other possible motif?

Related

JavaScript Type Problem: How do I assign the return value of a function to a variable, but not the function itself?

I am currently working with RPG maker MZ and try to write my first plugin. Now i do have not much experience with JavaScript, only with Java, and i think this error arises from the weaker typing system compared to java. I think that the source of the problem is, that my var filteredList gets a function as its value where it actually should had actually gotten the return value of the function. so my question would be: how do i assign filteredList the correct value?
In the game, the function was supposed to replace the standard way of determine Loot from enemies. The code with the problem is the following:
let actualDropList = new Array;
commonItemList.forEach(matchedElement => {
commonItemDataList.push($dataItems[matchedElement]);
console.log($dataItems[matchedElement]);
}
});
let CommonDropWorth = this.enemy().meta.HellsCommonDropBase /*+ (enemy.dataObject.meta.HellsCommonDropFlat * (this.enemy.level-1))*/;
var filteredList = commonItemDataList.filter((Item => Item.price <= CommonDropWorth));
var cleanFilteredList = function(){
return commonItemDataList.filter((Item => Item.price <= CommonDropWorth));
};
while (filteredList.length > 0){
let item;
if (filteredList.length > 1){
item = filteredList[Math.floor(Math.random()*filteredList.length)];
CommonDropWorth = CommonDropWorth - item.price;
}
else if(filteredList.length = 0){
item = filteredList[0];
CommonDropWorth = CommonDropWorth - item.price;
}
actualDropList.push(item);
filteredList = cleanFilteredList.apply;
}
return actualDropList;
the idea here was that each opponent has a "CommonDropWorth", which indicates the total value of common drops that this opponent drops. higher value = more drops. a while loop selects random items until the total value of the drops is close to the value of the "commondropWorth". items that have a smaller value than the commondropworth are filtered out by the function stored in the "cleanFilteredList" variable. now the variable "filteredList" is supposed to assign the return value of the function, but instead the function itself is assigned to it, and due to the type safety tabs this problem is not shown in the IDE. This leads to the following Error: TypeError
Cannot read property 'price' of undefined. So my question is: how do i assign the var filteredList the return value of the function and not the function itself? Important: The filteredList must be updated every time the commonDropWorth reduces, because otherwise it would make it possible to drop Items that are more worth.
P.s, to avoid other unnessesary questions in the future: how can i ensure that my code does not try to asign objects of the wrong type?
(Transparency note: i think my post was made invisible, as i made some errors during creation and some of the already given answers disappeared. This is technically a repost, but because of the circumstances, i didnt know how to get an answer on my first post.)
I think there is something wrong with your handling of lengths of the array.
while (filteredList.length > 0){
let item;
if (filteredList.length > 1){
item = filteredList[Math.floor(Math.random()*filteredList.length)];
CommonDropWorth = CommonDropWorth - item.price;
}
else if(filteredList.length = 0){
item = filteredList[0];
CommonDropWorth = CommonDropWorth - item.price;
}
actualDropList.push(item);
filteredList = cleanFilteredList.apply;
}
return actualDropList;
Three problems that I can see:
1. Wrong splitting of cases as 1 vs >1, instead of splitting as 0 versus >0
I think you have intended to split up the cases where the length is 1, from the cases where length is >1. This is not necessary, as the >1 part of the program will work just fine for the ==1 case.
2. Failing to handle the length == 0 case
The handling of length == 0 needs to make sure not to select one of the (zero!) items. Remember, when length == 0, you are not allowed to read item #0, just as when length = 10, you are not allowed to read item #10.
3. I am not sure the ".apply" function works in the way you use it.
Usually there are parentheses after .apply?
I usually put the filter in directly where it is needed, unless the function is unusually complicated. Here the boilerplate of creating a named function, and then applying it, is probably too much effort and opportunity for error, I think.
Try this, which fixes items 1 to 3 above.
while (filteredList.length >= 1){
const item = filteredList[Math.floor(Math.random()*filteredList.length)];
CommonDropWorth = CommonDropWorth - item.price;
actualDropList.push(item);
filteredList = commonItemDataList.filter((Item => Item.price <= CommonDropWorth))
}
return actualDropList;
Remember that you can be confident that the block inside the while loop begins with filteredList.length being 1 or more. (I prefer to call it >=1 than >0, because it helps me remember that it means "if I have at least one item on the list, I can select an item from the list".
Therefore you can get rid of the if (filteredList.length = 0). Incidentally, that should have been an == not a single =, but it doesn't matter because you are deleting it.

Algorithm : finding nearby value the fastest way

I have an array of sorted numbers, and a starting value. For the sake of simplicity, let's say the array has values from 1 to 20, and the starting value is 10.
The value to find can change every 5 seconds, based on user input. It can either increase or decrease and it always keeps in the range of values of the table.
The only thing I cannot know is whether the value is increasing or decreasing. I have come up with the (very) simple algorithm below.
Can you think of a way to improve it ?
Ideally, I think the best approach would be to run the two for loops simultaneously and return when value is found... Using workers for example ?
In my example, the "going down" for loops is exhausted before "going up" starts running. Which, idealy, shouldn't happen, since I'm trying to spread tries -1/+1 each time.
Btw : the reason why I'm trying to do this is because I have to run quite heavy functions in the for loops. The code is running in node.js context.
Here's a JSFiddle and the code below
const attempts = document.getElementById('attempts');
let attemptsCount = Number(attempts.textContent);
const lastValue = 10;
const valueToFind = 16; //this must be found in the least possible number of attempts
const table = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];
const lookup = () => {
for (var i = lastValue; i > 0; i--) {
if (table[i] == valueToFind) {
alert('Found going down');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
for (var i = lastValue; i < table[table.length-1]; i++) {
if (table[i] == valueToFind) {
alert('Found going up');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
}
//find new value
lookup();
Right now, each for loop you have runs async from one another...so one side will always finish before the other side starts...which is not ideal.
Remember that for loops are set up to initialize, check if bool statement = true, and set next step...so like if statements, you can implement multiple statements in each scenario.
Reducing the loop attempts can be simple as doing it at the same time:
const lookup = () => {
for (var up = lastValue, down = lastValue-1; up < table[table.length-1] || down > 0; up++, down--) {
if (up < table[table.length-1] && table[up] == valueToFind) {
alert('Found going up');
return;
} else if (down > 0 && table[down] == valueToFind) {
alert('Found going down');
return;
} else {
attemptsCount++;
attempts.textContent = attemptsCount;
}
}
Your JSFiddle updated

Javascript sorting array twice (different sort methods)

I have an array that at page load sorts the array how I want, depending on the current date it shows the objects that have a future date and then shows the objects with past dates, lets call this datesToPlay.
I have two radio buttons to call on the method to sort the same array, and at page load it sorts the array perfectly fine how I mentioned above. The problem is when I sort the array with the other sorting method, createdAt which simply sorts the array by the date of creation. This method sorts it fine, but when I press the other radio to sort by datesToPlay it doesn't sorts the array.
function SortByPlayTime(a, b){
var currentDate = new Date();
if(lastDateOfObjectsInArray > currentDate){
if(a.attributes.start >= currentDate){
if(a.attributes.start > b.attributes.start && b.attributes.start >= currentDate)
return 1;
else
return -1;
} else if(b.attributes.start >= currentDate){
if(b.attributes.start > a.attributes.start)
return -1;
else
return 1;
}
else{
if(a.attributes.start > b.attributes.start)
return 1;
else
return -1;
}
} else{
if(a.attributes.start > b.attributes.start)
return -1;
else
return 1;
}
function SortByCreation(a, b){
if(a.attributes.createdAt > b.attributes.createdAt)
return 1;
else
return -1;
Basically what Im doing is I have an array with all the objects im trying to sort, this array varies in size and can be like 1000 or more objects.
In function loadArrayToShowFilters() what Im doing is to prepare a new array that will be shown in a table (see comments above for screens). This is cause Im mimicking a table but actually Im doing all the work with arrays; this array will always be 100 length or less.
function loadArrayToShowFilters() {
//array = the array of objects Im trying to filter
var sizeArrayToShow;
if(array.length < 100)
sizeArrayToShow = array.length;
else
sizeArrayToShow = 100;
arrayTableToShow = [];
//arrayTableToShow = This is the array that holds the objects that are shown on the table
for (var i = 0; i < sizeArrayToShow; i++) {
arrayTableToShow[i] = array[i];
};
Events that trigger the sorts: event click on two radio buttons.
Code that performs the actual sort: on the event click of each radio button, I just do array.sort(SortByCreation) and like so respectively.
Sample data: {"start":{"__type":"Date","iso":"2018-02-01T11:00:00.000Z"},"end":{"__type":"Date","iso":"2018-02-01T12:00:00.000Z"},"createdAt":"2018-01-29T20:37:51.477Z","updatedAt":"2018-02-23T03:12:15.968Z","objectId":"dSVZXFAIyf"}
It's basically just an array with objects, each object with a variable attributes with includes variables start and createdAt which are used to do the sorting
Events:
'click #lastCreated'(event){
orderArregloCreatedAt();
},
'click #nextToPlay'(event){
orderArregloPlayTime();
}
function orderArregloCreatedAt() {
array.sort(SortByCreation);
loadArrayToShowFilters();
}
function orderArregloPlayTime() {
array.sort(SortByPlayTime);
loadArrayToShowFilters();
}
Information needed to resolve this issue is still sorely lacking from this question. But I think the fault lies in the sorting algorithm of SortByPlayTime.
This is a bit of a wild shot, but please can you tell me if the following change delivers:
expected sort order at page load?
expected sort order after clicking the radio button?
the same results for both, even if it's wrong?
Code change:
function SortByPlayTime(a, b) {
var currentDate = new Date();
// a is future, b is past, so a shows above b = -1
if (a.attributes.start >= currentDate && b.attributes.start < currentDate) return -1;
// a is past, b is future, so a shows below b = 1
if (a.attributes.start < currentDate && b.attributes.start >= currentDate) return 1;
// both a and b are similarly future or past so compare on their values alone, in ascending order
// if a > b then it should show below b, = positive result
return a.attributes.start - b.attributes.start;
}

json array check if there does not need to insert in localstorage?

I need to check a JavaScript array to see if there are duplicate values ​​. What is the easiest way to do this ? I just need to check whether the values ​​already exist if there is not need to go into json array.
function cek() {
resi_or_code = document.getElementById('code_or_resi').value;
resi = resi_or_code.split(',');
if($.trim(resi_or_code) != ''){
location.href = base_url + 'resi/' + encodeURIComponent(resi_or_code);
}
if (localStorage.daftar_data){
daftar_data = JSON.parse(localStorage.getItem('daftar_data'));
$("#riwayat").toggle();
}
else {
daftar_data = [];
}
for (y in daftar_data){
var q = daftar_data[y].resis;
for (x in resi){
console.log(q);
if (q === resi[x])
{
console.log('Value exist');
}else{
console.log('Value does not exist');
daftar_data.push({'resis':resi[x]});
localStorage.setItem('daftar_data', JSON.stringify(daftar_data));
}
}
}
}
If i understand your question and code right, you basically have an array of objects where each object has key resis
If that is the case, below code might help
var valueArray = ar.map(function(item) {
return item.resis;
})
// To check for duplicate
if(valueArray.indexOf(value) !== -1) {
// Duplicates
} else {
// No duplicate
}
In your case,
ar would be daftar_data.
I am really not sure what your value is. is it resi?
Basically, you should try replacing your for loop with the above code.
By far the simplest way is to simply sort your array using Array.sort(). This will perform well and reduces you duplicate check to a simple for-loop that compares each value with its neighbor.
Solutions that attempt to avoid sorting will almost certainly scale very badly.
So to recap and show some code:
daftar_data.sort();
for (var index = 0; index < daftar_data.length - 1; index++)
{
if (daftar_data[index] === daftar_data[index+1]) {
// Found a duplicate
}
}
If the natural sort order of the objects don't work for you, supply a function to the sort function, like so:
daftar_data.sort(function(a, b) {
// return any value > 0 if a is greater, < 0 if b is greater
// and 0 if they are equal.
});
Note that in this form, you can actually check for the duplicate in your compare function.

Trouble pushing to an array in JS

Below is just a section of my code but I know it's problematic because I can't get it to return any value except 'undefined'. I have been over this for hours and cannot figure it out.
I want to be able to input a number and have its factors pushed to an array. I have tested it by alerting the first item in the array and I get nothing. I'm sure this is a pretty easy but I just can't figure it out. Here is the code:
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
//determine factors and push to array for later use
var factorsArray = [];
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
return factorsArray.push[i];
} else {
continue;
}
}
};
factors(numberInQuestion);
alert(factorsArray[0]);
Thanks for any help!
you can only return one value
you must use (), not [] for calling push
factorsArray should be local to factors (put the definition inside the function)
the else { continue; } is useless
Here is the fully corrected code:
var numberInQuestion = prompt("Of what number are you wanting to find the factors of?");
//determine factors
function factors(numberInQuestion){
var factorsArray = []; // make it local
for (var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0){
factorsArray.push(i); // use (), and don't return here
} // no need for else { continue; } because it's a loop anyway
}
return factorsArray; // return at the end
};
var result = factors(numberInQuestion); // assign the result to a variable
alert(result);
Here's a JSFiddle.
You have an error in your pushing syntax. Correct syntax for pushing is -
factorsArray.push(i);
Also returning immediately from the function after finding the first divisor will not give you the full list. You probably want to return after you've found out all the divisors.
Taking all of the above into consideration, you should rewrite your function as follow -
function factors(numberInQuestion){
for(var i = 2; i < numberInQuestion - 1; i++){
if(numberInQuestion % i === 0) {
factorsArray.push(i);
}
}
}
and you will be OK.
You've coded this so that when you find the first factor your function returns immediately. Just get rid of the return keyword in that statement. (What "return" means in JavaScript and other similar languages is to immediately exit the function and resume from where the function was called.)
Oh, also, you call functions (like .push()) with parentheses, not square brackets.
The function should not return when pushing to the array. Return the array after executing the loop. The else clause is also unnecessary.
var numberInQuestion = prompt("Of what number are you wanting to find the largest prime factor?");
function factors(numberInQuestion){
var factorsArray = [];
for(var i = 2; i < numberInQuestion-1; i++){
if(numberInQuestion % i === 0 && isPrime(i)){
factorsArray.push(i);
}
}
return factorsArray;
};
var factors = factors(numberInQuestion);
alert(factors[factors.length-1]);
//From: http://stackoverflow.com/questions/11966520/how-to-find-prime-numbers
function isPrime (n)
{
if (n < 2) return false;
var q = Math.sqrt (n);
for (var i = 2; i <= q; i++)
{
if (n % i == 0)
{
return false;
}
}
return true;
}
Given the purpose of the example two items must be considered
The code does not determine if the number is actually prime. The code will return the smallest factor possible since the loop starts at two and increments, then returns the first element in the array. The largest factor would actually be the last element in the array. I have corrected the example to find the greatest prime factor. You can test it via this fiddle: http://jsfiddle.net/whKGB/1/

Categories

Resources