why does this list-sorter crash? - javascript

This page crashes on run:
<head>
<script>
var list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1];
var listOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
var loopCount = 0;
while (list !== listOrdered) {
if (list[loopCount] > list[loopCount + 1]) {
var lower = list[loopCount + 1];
var higher = list[loopCount];
list[loopCount] = lower;
list[loopCount + 1] = higher;
}
if (loopCount === 19) {
loopCount = 0;
} else {
loopCount = loopCount + 1;
}
}
</script>
</head>
</html>
What could i do to stabilize it?
As far as i am aware, the logic is as correct as i intend.
This is purely recreational experimentation.
After further development, the problem of comparison no longer exists:
<!doctype html>
<html>
<head>
<script>
var sweeps = 0;
var swaps = 0;
var list = [25, 21, 4, 23, 32, 2, 40, 8, 27, 9, 29, 33, 31, 14, 12, 16, 35, 18, 37, 20, 39, 19, 38, 17, 36, 15, 34, 13, 6, 11, 30, 10, 28, 7, 26, 5, 1, 3, 22, 24];
var loop = 0;
var swapped = 0;
var ordered = 0;
while (ordered !== 1) {
if (list[loop] > list[loop + 1]) {
var lower = list[loop + 1];
var higher = list[loop];
list[loop] = lower;
list[loop + 1] = higher;
swapped = 1;
swaps = swaps + 1;
}
if (loop === list.length - 1) {
if (swapped === 0) {
ordered = 1;
}
swapped = 0;
loop = 0;
} else {
loop = loop + 1;
}
sweeps = sweeps + 1;
}
alert("list: " + list);
alert("Sweeps: " + sweeps + ", Swaps: " + swaps);
</script>
(Like how “cooky monster” suggests)

Because the array objects will never be the same object even if their contents end up the same (JavaScript doesn't compare values when using the comparison operators on objects (including arrays), but whether they are identical objects). You could serialize them both into a string and compare the strings, however, for a quick-and-dirty comparison that fits into your approach:
<head>
<script>
var list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1];
var listOrdered = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];
var loopCount = 0;
while (JSON.stringify(list) !== JSON.stringify(listOrdered)) {
if (list[loopCount] > list[loopCount + 1]) {
var lower = list[loopCount + 1];
var higher = list[loopCount];
list[loopCount] = lower;
list[loopCount + 1] = higher;
}
if (loopCount === 19) {
loopCount = 0;
} else {
loopCount = loopCount + 1;
}
}
alert(JSON.stringify(list)) // [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
</script></head></html>
JSON.stringify is not available by default in older browsers, so if you need to support older browsers, you can use https://github.com/douglascrockford/JSON-js/blob/master/json2.js

Instead of doing a comparison, I'd just use a flag to indicate if you had to swap values during an iteration. If so, reset the counter to 0 and reset the flag. If not, you're done.
var list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 19, 17, 15, 13, 11, 9, 7, 5, 3, 1];
var loopCount = 0;
var swapped;
while (true) {
if (list[loopCount] > list[loopCount + 1]) {
var lower = list[loopCount + 1];
var higher = list[loopCount];
list[loopCount] = lower;
list[loopCount + 1] = higher;
swapped = true; // Set the flag indicating we swapped a pair of values.
}
if (loopCount === 19) { // At the end of a full iteration...
if (swapped) { // check to see if we had occasion to swap..
swapped = false;// and if so, reset the flag, and start again..
loopCount = 0;
} else
break; // or if not, we're done sorting.
} else {
loopCount = loopCount + 1;
}
}
This will be much faster than any sort of array comparison.

Related

Is there a more efficient way to display the sum of two arrays using For Loops in JavaScript?

I want the end result to display "276 + 351 = 627". Is there a more efficient way to do so while using for loops?
This is a practice question I found online, so the stuff after the 2 arrays is what I've come up with.
let arr_1 = [3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2];
let arr_2 = [9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26];
let sum1 = 0;
let sum2 = 0;
for (let i = 0; i < arr_1.length; i++) {
sum1 += arr_1[i];
}
for (let j = 0; j < arr_2.length; j++) {
sum2 += arr_2[j];
}
let total = sum1 + sum2;
console.log(`${sum1} + ${sum2} = ${total}`);
The reduce function allows you to write it in a very short manner:
const arr_1 = [3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2],
arr_2 = [9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26],
add = arr => arr.reduce((sum, n) => sum + n),
sum1 = add(arr_1),
sum2 = add(arr_2),
total = sum1 + sum2;
console.log(`${sum1} + ${sum2} = ${total}`);
this way
const
doSum = arr => arr.reduce((a,c)=>a+c,0) // let zero value, if arr is empty
, arr_1 = [ 3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2 ]
, arr_2 = [ 9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26 ]
, sum1 = doSum(arr_1)
, sum2 = doSum(arr_2)
, total = sum1 + sum2
;
console.log(`${sum1} + ${sum2} = ${total}`)
There many way to loop through a array if you read the MDN Docs Link Here.
One of the way is reduce() which work with almost all browsers but i would prefer to use forEach() as it is one of oldest proto on arrays.. and here is how it is done
let arr_1 = [3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2];
let arr_2 = [9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26];
let sum1 = 0
let sum2 = 0
let total = 0
arr_1.forEach((el) => {
sum1 += el
});
arr_2.forEach((el) => {
sum2 += el
});
total = sum1 + sum2
console.log(`${sum1} + ${sum2} = ${total}`);
JSFiddle Link
Assuming both arr_1 and arr_2 have the same length, you only need one loop. This is as efficient (as in speed/performance) as you'll get:
let sum1 = 0, sum2 = 0,
arr_1 = [3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2],
arr_2 = [9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26];
for (let i = 0; i < arr_1.length; i++) {
sum1 += arr_1[i], sum2 += arr_2[i];
}
let total = sum1 + sum2;
console.log(`${sum1} + ${sum2} = ${total}`);
Plain for loops are typically faster than more high level looping functions, so you already have the best performing loop possible.
You could also use this for arrays of different lengths by looping the larger one, still only doing one for loop:
let sum1 = 0, sum2 = 0,
arr_1 = [3, 5, 22, 5, 7, 2, 45, 75, 89, 21, 2, 6, 40, 4],
arr_2 = [9, 2, 42, 55, 71, 22, 4, 5, 90, 25, 26];
for (let i = 0; i < arr_1.length; i++) {
sum1 += arr_1[i], sum2 += arr_2[i] || 0;
}
let total = sum1 + sum2;
console.log(`${sum1} + ${sum2} = ${total}`);
When arr_2 runs out, it will start outputting undefined. The arr_2[i] || 0 expression will use the secondary value in that case.
An alternative would be to check if the offset exists:
for (let i = 0; i < arr_1.length; i++) {
sum1 += arr_1[i];
if(arr_2[i]) sum2 += arr_2[i];
}

JavaScript split array in half juxtapose the first half with second half

What is the method to evenly split an array into two. Then, position the second half underneath the first all for the purpose of comparing whether or not a new final array should receive a zero or one in the slots.
var master_array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38];
var first_half = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19];
var second_half = [20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38];
var final_usable_array_reduced = [];
So, given a form with 38 check boxes, if the 5th, 19th, 37th, and 38th check boxes were checked, the final_usable_array_reduced would be
final_usable_array_reduced = [0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1];
final_usable_array_reduced[4] = **represents the 5th <strong>or</strong> 24th box being checked**
final_usable_array_reduced[18] = **represents the 19th <strong>or</strong> 38th boxes being checked**
I think you can implement this with a simple for loop over half the master_array, oring the values in the bottom half of the array with those in the top half:
var master_array = new Array(38).fill(0);
master_array[4] = 1;
master_array[18] = 1;
master_array[36] = 1;
master_array[37] = 1;
let len = master_array.length / 2;
final_usable_array_reduced = new Array(len);
for (let i = 0; i < len; i++) {
final_usable_array_reduced[i] = master_array[i] | master_array[i + len];
}
console.log(final_usable_array_reduced);
Check this one:
var array = [0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0];
var firstHalf = array.slice(0,array.length/2);
var secondHalf = array.slice(array.length/2);
var result = firstHalf.map(function(e,i){
return e || secondHalf[i];
});
console.log(result);
What I'm doing here is spliting the array into two halfs with slice (considering that the array elements are even, of course), and after that I map the first one returning 1 (or true, is the same) if firstArray[i] or secondArray[1] is 1.
Consider the following.
$(function() {
function addChecks(count, tObj, cont) {
var i;
if (cont == undefined) {
i = 0;
} else {
i = parseInt($("input:last").val()) - 1;
count = i + count;
}
for (i; i <= count; i++) {
$("<input>", {
type: "checkbox",
value: (i + 1),
title: (i + 1)
}).appendTo(tObj);
}
}
function checksToArray() {
var arr = [];
$("input[type='checkbox']").each(function() {
arr.push($(this).prop("checked"));
});
return arr;
}
function compHalfArr(a) {
var arr = [];
var h = Math.floor(a.length / 2);
for (var i = 0; i <= h; i++) {
arr.push(a[i] || a[(i + h)]);
}
return arr;
}
addChecks(14, $(".section-1"));
addChecks(14, $(".section-2"), true);
$("button").click(function() {
var allChecks = checksToArray();
var compChecks = compHalfArr(allChecks);
$(".results").html("<span>" + compChecks.join("</span><span>") + "</span>").find("span:last").remove();
});
});
.checks input {
margin-right: 20px;
}
.results span {
display: inline-block;
font-family: Arial, sans-serif;
width: 40px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="checks section-1"></div>
<div class="checks section-2"></div>
<button>Check</button>
<div class="results"></div>
You can do a loop using a halfway marker.

Counting iterations of 1 in an array

My goal is to count iterations of 1 in an array.
I have this code:
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
var count = 0;
for(var i = 0; i < array.length; ++i){
if(array[i] === 1)
count++;
}
console.log(count);
Right now, it logs 5, but including "10" it should log 6, since "10" also contains a 1. What code can I use for this?
What about:
var count = array.toString().split('1').length - 1;
You can use filter method in combination with length property in order to write a more cleaner solution.
Also, use join and split methods in order to achieve your requirement.
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
console.log(array.join('').split('').filter(a=>a==1).length);
or using reduce method.
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
console.log(array.join('').split('').reduce((c,i)=> i==1 ? c+1 :c).length);
Just convert every item to string, and then check if 1 belongs to that number or not.
So for number 10, the string is '10' and then '10'.indexOf('1') equals to 0. So every time 1 is found within the string, you increment the counter.
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
var count = 0;
for (var i = 0; i < array.length; ++i) {
if (array[i].toString().indexOf('1') >= 0)
count++;
}
console.log(count);
You need to split your numbers into digits and iterate over each digit (which is a character) and compare with it. Use Object#toString to parse the number into the string, split into characters by String#split and using Array#forEach iterate over characters and do the same comparison there.
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
var count = 0;
for(var i = 0; i < array.length; ++i) {
var numberAsString = array[i].toString();
numberAsString.split('').forEach(char => {
if(char === '1') {
count++
}
});
}
console.log(count);
You'll need to convert each number to a string and use indexOf
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
var count = array.reduce(function(p,c){
if(c.toString().indexOf("1")>-1)
p++;
return p;
},0);
console.log(count);
You can Array#join the array items to a string and count using String#match with a regular expression:
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
// the || [] is a fallback in case there is no 1, and match returns null
var result = (array.join('').match(/1/g) || []).length;
console.log(result);
You could check every character of the joined string.
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1],
count = 0,
i,
temp = array.join('');
for (i = 0; i < temp.length; ++i) {
if (temp[i] === '1') {
count++;
}
}
console.log(count);
var array = [10, 3, 22, 40, 1, 40, 1, 22, 1, 0, 3, 53, 1, 1];
var count = 0;
for(var i = 0; i < array.length; ++i){
if( array[i] === 1 || array[i].toString().includes("1") )
count++;
}
console.log( count );

compare element in two arrays

I want to compare each element of array real with each element of array number. And if there is any matches push them in array add so I can see them. In this case add must be 2,3,6,10,14 if code is good.
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script>
var real=[1,2,3,4,5,6,7,8,10,14,16,233,235,245,2,5,7,236,237];
var number=[2,3,6,10,12,13,14,172,122,234];
var add=[];
for (k=0; k<number.length; k++)
{
for (w=0; w<real.length; w++)
{
if (number[k]==real[w]);
{
add.push(number[k],real[w]);
}
};
};
document.write(add+"<br>");
</script>
Here is a short and simple solution using Array.forEach and Array.indexOf functions:
var real = [1,2,3,4,5,6,7,8,10,14,16,233,235,245,2,5,7,236,237],
number = [2,3,6,10,12,13,14,172,122,234],
add = [];
real.forEach(function(v) {
if (number.indexOf(v) !== -1 && this.indexOf(v) === -1) this.push(v);
}, add);
console.log(add); // [2, 3, 6, 10, 14]
A more elegant and readable solution:
var matched = [];
real.forEach(function(realNum) {
number.forEach(function(numberNum) {
if(realNum == numberNum && matched.indexOf(realNum) === -1) {
matched.push(realNum);
}
});
});
Here's one way you can do it using ES6:
var real = [1, 2, 3, 4, 5, 6, 7, 8, 10, 14, 16, 233, 235, 245, 2, 5, 7, 236, 237];
var number = [2, 3, 6, 10, 12, 13, 14, 172, 122, 234];
var filtered = real.filter(x => number.indexOf(x) > -1);
var unique = new Set(filtered);
document.body.innerHTML = [...unique];
try this way...
Sorted the main Array, removed duplicates and the find the common elements from both the arrays.
var main = [1,2,3,4,5,6,7,8,10,14,16,233,235,245,2,5,7,236,237];
var compare = [2,3,6,10,12,13,14,172,122,234];
function compareNumbers(a, b) {
return a - b;
}
console.log('Sorted Array :', main.sort(compareNumbers) );
// Sorted Array : [1, 2, 2, 3, 4, 5, 5, 6, 7, 7, 8, 10, 14, 16, 233, 235, 236, 237, 245]
Array.prototype.unique = function() {
var unique = [];
for (var i = 0; i < this.length; i++) {
var current = this[i];
if (unique.indexOf(current) < 0) unique.push(current);
}
return unique;
}
console.log('Unique Array Elements:', main.unique() );
// Unique Array Elements: [1, 2, 3, 4, 5, 6, 7, 8, 10, 14, 16, 233, 235, 236, 237, 245]
function commonElements(arr1, arr2) {
var common = [];
for (var i = 0; i < arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j] ) {
common.push( arr1[i] );
j == arr2.length; // To break the loop;
}
}
}
return common;
}
console.log('Common Elements from Both Arrays : ', commonElements(main.unique(), compare.unique()) );
//Common Elements from Both Arrays : [2, 3, 6, 10, 14]

How to programmatically identify where n would fit in this sequence?

I have a number I want to conform to the closest value in the following sequence:
2, 5, 9, 12, 15, 19, 22, 25, 29, 32, 35, 39, 42...
If 10 is passed, it would become 12, 13 would become 15, 17 would become 19.
How would I approach this in a function?
If you don't know whether the array is sorted, you could use code like this to find the value in the array that is the closest to the passed in value (higher or lower):
var list = [2, 5, 9, 12, 15, 19, 22, 25, 29, 32, 35, 39, 42];
function findClosestValue(n, list) {
var delta, index, test;
for (var i = 0, len = list.length; i < len; i++) {
test = Math.abs(list[i] - n);
if ((delta === undefined) || (test < delta)) {
delta = test;
index = i;
}
}
return(list[index]);
}
If you want the closest number without going over and the array is sorted, you can use this code:
var list = [2, 5, 9, 12, 15, 19, 22, 25, 29, 32, 35, 39, 42];
function findClosestValue(n, list) {
var delta, index;
for (var i = 0, len = list.length; i < len; i++) {
delta = n - list[i];
if (delta < 0) {
return(index ? list[index] : undefined);
}
index = i;
}
return(list[index]);
}
Here is a jsFiddle with a solution that works for an infinite series of the combination "+3+4+3+3+4+3+3+4+3+3+4....." which seems to be your series. http://jsfiddle.net/9Gu9P/1/ Hope this helps!
UPDATE:
After looking at your answer I noticed you say you want the closes number in the sequence but your examples all go to the next number in the sequence whether it is closest or not compared the the previous number so here is another jsfiddle that works with that in mind so you can choose which one you want :).
http://jsfiddle.net/9Gu9P/2/
function nextInSequence(x){
//sequence=2, 5, 9, 12, 15, 19, 22, 25, 29, 32, 35, 39, 42
var i= x%10;
switch(i){
case 2:case 5:case 9: return x;
case 0:case 1: return x+ 2-i;
case 3:case 4: return x+5-i;
default: return x+9-i;
}
}
alert(nextInSequence(10))

Categories