I'm trying to write a tool for visualizing the bubble sort algorithm.
The array arr holding all the values, that is to be sorted, is a global variable. The user clicks the "Fill" button btnFill to fill the array with unsorted, random numbers using the fillArray function. The function returns an array of objects: {val: x, col: "y"} where x is the value and col is a color class used for CSS.
When the array is filled, if the user clicks the "sort" button btnSort, the bubbleSort function is invoked where I guess my problem is:
This function saves a copy of the array arr on every iteration of the inner loop. This is an idea that I had since I was having a lot of issues using setInterval to animate - I could just save snapshots of the array during every stage of the sorting, and then pass it to the draw function so that there wouldn't be any JavaScript weirdness combining loops and intervals.
The function finishes running and is expected (by me at least) to return an array filled with copies of the arr array from every loop iteration.
The actual behavior which I have tried to understand for hours is that the snapShot array is filled with arrays of a sorted arr. All elements are the same - sorted arrays. Doesn't make sense to me since when debugging it comes out as sorted in console.log when it enters the sorting loop for the first time.
I appreciate any help greatly, thank you!
--EDIT--
I'm aware that the snapShot array gets sent as an array of arrays and will not be drawn to the screen but the problem is somewhere before that. That part was changed for debugging reasons
const btnFill = document.querySelector("#btnFill");
const btnSort = document.querySelector("#btnSort");
const container = document.querySelector(".container");
let arr = [];
btnFill.addEventListener("click", function () {
arr = fillArray();
draw(arr);
});
btnSort.addEventListener("click", function () {
let sorted = bubbleSort();
draw(sorted);
});
function bubbleSort() {
let snapShots = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j].val > arr[j + 1].val) {
let tmp = arr[j].val;
arr[j].val = arr[j + 1].val;
arr[j + 1].val = tmp;
snapShots.push([...arr]);
}
}
}
return snapShots;
}
function fillArray() {
const tmp = [];
const len = 50;
for (let i = 0; i < len; i++) {
tmp[i] = { val: Math.floor(Math.random() * 100 + 1), col: "red" };
}
return tmp;
}
function draw(array) {
container.innerHTML = "";
for (let i = 0; i < array.length; i++) {
const tmp = document.createElement("div");
tmp.style.height = array[i].val + "%";
tmp.classList.add("bar", array[i].col);
container.appendChild(tmp);
}
}
The reason that it's not working like you want it is because you are doing shallow copies of the array, but the objects in each position are the same references.
This means that this part of the code:
let tmp = arr[j].val;
arr[j].val = arr[j + 1].val;
arr[j + 1].val = tmp;
Is changing the object that every snapshot element is pointing in the same position. And that's why you get every array sorted, because you are creating new arrays with the same references to the objects.
To get what you want you can do a deep copy instead, which also creates new references of the nested values.
function bubbleSort() {
let snapShots = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j].val > arr[j + 1].val) {
let tmp = arr[j].val;
arr[j].val = arr[j + 1].val;
arr[j + 1].val = tmp;
snapShots.push(JSON.parse(JSON.stringify(arr)));
}
}
}
return snapShots;
}
Other solution (and simpler) is to change the position of the object in the array instead of changing the property val of the object:
function bubbleSort() {
let snapShots = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = 0; j < arr.length - 1 - i; j++) {
if (arr[j].val > arr[j + 1].val) {
let tmp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = tmp;
snapShots.push([...arr]);
}
}
}
return snapShots;
}
Related
I'm trying to solve a beginner problem on leetcode.
Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
My solution works well on some of the testcases, but fail on this:
*
Example:
Input: nums = [3,3], target = 6
Output: [0,1]
This is my code:
let nums = [3, 3];
let target = 6;
var twoSum = (nums, target) => {
for (let i = 0; i < nums.length; i++) {
let result = [];
if (target === nums[i] + nums[i + 1]) {
result.push(nums.indexOf(nums[i]));
result.push(nums.indexOf(nums[i + 1]));
return result;
}
}
};
console.log(twoSum(nums, target));
Output is [0,0] here, instead of [0,1].
Where did the logic fail? I clearly pushed nums[i + 1] to the array as the second value.
Your algorithm is incorrect because the elements need not be adjacent to each other. Instead, you should use a nested loop to add each element of the array with every element after it.
var twoSum = (nums, target) => {
for (let i = 0; i < nums.length; i++) {
for(let j = i + 1; j < nums.length; j++){
if(nums[i] + nums[j] === target) return [i, j];
}
}
};
Please help me to solve this leetcode problem using javascript as I am a beginner and dont know why this code is not working
Ques: Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.
Find all the elements of [1, n] inclusive that do not appear in this array.
var findDisappearedNumbers = function (nums) {
var numLength = nums.length;
nums.sort(function (a, b) { return a - b });
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
}
}
for (var k = 0; k < nums.length; k++) {
for (var j = 1; j <= numLength; j++) {
if (nums[k] !== j) {
return j;
}
}
}
};
if there is any error in my code please let me know;
i have done the following thing
first i have sorted the array in ascending order
then i have cut all the duplicate elements
then i have created loop that will check if nums[k] !== j ;
and it will return j which is the missing number;
for example this is the testcase [4,3,2,7,8,2,3,1]
first my code will sort this in ascending order [1,2,2,3,3,4,7,8]
then it will remove all duplicate elements and it will return [1,2,3,4,,7,8]
and then it will check nums[k] is not equal to j and it will print j
I think it'd be easier to create a Set of numbers from 1 to n, then just iterate through the array and delete every found item from the set:
var findDisappearedNumbers = function(nums) {
const set = new Set();
for (let i = 0; i < nums.length; i++) {
set.add(i + 1);
}
for (const num of nums) {
set.delete(num);
}
return [...set];
};
console.log(findDisappearedNumbers([4,3,2,7,8,2,3,1]));
To fix your existing code, I'm not sure what the logic you're trying to implement in the lower section, but you can iterate from 1 to numLength (in the outer loop, not the inner loop) and check to see if the given number is anywhere in the array. Also, since you're mutating the array with splice while iterating over it in the upper loop, make sure to subtract one from i at the same time so you don't skip an element.
var findDisappearedNumbers = function(nums) {
var numLength = nums.length;
nums.sort(function(a, b) {
return a - b
});
for (var i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] === nums[i]) {
nums.splice(i, 1);
i--;
}
}
const notFound = [];
outer:
for (var j = 1; j < numLength; j++) {
for (var k = 0; k < nums.length; k++) {
if (nums[k] === j) {
continue outer;
}
}
notFound.push(j);
}
return notFound;
};
console.log(findDisappearedNumbers([4, 3, 2, 7, 8, 2, 3, 1]));
#CertainPerformance certainly cracked it again using the modern Set class. Here is a slighly more conservative approach using an old fashioned object:
console.log(missingIn([4,3,2,7,8,2,3,1]));
function missingIn(arr){
const o={};
arr.forEach((n,i)=>o[i+1]=1 );
arr.forEach((n) =>delete o[n] );
return Object.keys(o).map(v=>+v);
}
My solution for the problem to find the missing element
var findDisappearedNumbers = function(nums) {
const map={};
const result=[];
for(let a=0;a<nums.length;a++){
map[nums[a]]=a;
}
for(let b=0;b<nums.length;b++){
if(map[b+1]===undefined){
result.push(b+1)
}
}
return result;
};
Example 1:
Input: nums = [4,3,2,7,8,2,3,1]
Output: [5,6]
Example 2:
Input: nums = [1,1]
Output: [2]
I have a combinatoric script that's working fine, actually got most of it from the IBM dev website. But I want to be able to not just show the possible combinations, but also extract the numbers on each combination and get the product of the entire numbers. The project am working on mixes numbers (quantity) with strings (codename). So after combining them, i extract the number from each string and get the product of all the numbers in each combination. As shown;
[A2,B4,C5] = 2*4*5 = 40
Here is my javascript code that gets the combination, not to worry, I ran it with a test array of numbers 1-6, without the characters as shown above.
var Util = function() {
};
Util.getCombinations = function(array, size, start, initialStuff, output) {
if (initialStuff.length >= size) {
output.push(initialStuff);
} else {
var i;
for (i = start; i < array.length; ++i) {
Util.getCombinations(array, size, i + 1, initialStuff.concat(array[i]), output);
}
}
}
Util.getAllPossibleCombinations = function(array, size, output) {
Util.getCombinations(array, size, 0, [], output);
}
// Create an array that holds numbers from 1 ... 6.
var array = [];
for (var i = 1; i <= 6; ++i) {
array[i - 1] = i;
}
var output = [];
var resultArray = [];
Util.getAllPossibleCombinations(array, 4, output);
for(var j=0; j<output.length; j++) {
resultArray += output[j] + "=" + "<br />";
}
document.getElementById("test").innerHTML = resultArray;
});
I tried running this code inside the last for loop to get my multiplication, but it's just not executing, i must be doing something wrong. Here is the code;
var inputval = output[j].replace(/[^,.0-9]/g, '');
inputval = inputval.slice(0, -1);
var hoArray = inputval.split(',');
var cunt= hoArray.length;
var ans=1;
for(var m=0; m<cunt; m++)
{
ans *= hoArray[m];
}
Thanks for your assistance in advance.
walk the array then walk the string, then cast and see if it is an integer then tally and sum the product.
let array = ['A20', 'B11', 'C5'];
function getProduct(ar) {
let product = 1;
for (let x of ar) {
let semiProduct = [];
for (let i of x) {
if (Number.isInteger(+i)) {
semiProduct.push(i);
}
}
product *= semiProduct.join('');
}
return product;
}
console.log(getProduct(array))
You could also use a regular expression.
let array = ['A20', 'B11', 'C5'];
function getProduct(ar) {
let product = 1;
for (let x of ar) {
product *= x.match(/\d+/)[0];
}
return product;
}
console.log(getProduct(array))
If you want a way to generate permutations, you can utilize a generator to make things more concise.
let array = ['A20', 'B11', 'C5'];
function* permu(arr, l = arr.length) {
if (l <= 0) yield arr.slice();
else
for (var i = 0; i < l; i++) {
yield* permu(arr, l - 1);
const j = l % 2 ? 0 : i;
[arr[l - 1], arr[j]] = [arr[j], arr[l - 1]];
}
}
console.log(
Array.from(permu(array))
);
When I run that code in the console it throws an error because output[j] is an array [1,2,3,4] and it looks like you're expecting it to be a string. Arrays do not have a replace method in JS.
You should run this:
var count= hoArray.length;
var ans=1;
for(var m=0; m<count; m++)
{
ans *= hoArray[m];
}
And put output[j] instead of hoArray. And don't do any of this:
var inputval = output[j].replace(/[^,.0-9]/g, '');
inputval = inputval.slice(0, -1);
var hoArray = inputval.split(',');
This question already has answers here:
How to find the sum of an array of numbers
(59 answers)
Closed 6 years ago.
How can I turn this into a function that takes an array of any length and gives you the total?
var points = new Array(100);
for (var i = 0; i < 100; i++) {
points[i] = i + 1;
}
for(var i = 0; i < points.length; i++) {
console.log(points[i]);
}
You could do it in two loops, but you might as well just do one loop that does both tasks.
var array = [],
sum = 0;
for (var i = 1; i <= 10000; i++) {
array[i-1] = i;
sum += i;
}
If you want to generalize the task of finding the sum of an array, you can use a function like so:
function arraySum(array) {
var sum = 0;
for (var i = 0; i < array.length; i++)
sum += array[i];
return sum;
}
For those who can understand it though, using reduce is a best answer:
function arraySum(array) {
return array.reduce(function(a,b){return a+b}, 0);
}
You can do get the sum using the for loop itself simply by using a variable
var points = new Array(100),
sum = 0;
for (var i = 0; i < 100; i++) {
points[i] = i + 1;
}
for (var i = 0; i < points.length; i++) {
sum += points[i];
}
console.log(sum);
You can reduce these two operations using fill() and forEach() to generate the array and reduce() to get the sum
var points = new Array(10000); // create an array of size 10000
points.fill(1); // fill it with 1 which helps ti=o iterate using foreach
points.forEach(function(v, i) { // iterate the array, you can also use simple for loop here
points[i] = v + i; // update the value
});
var sum = points.reduce(function(a, b) { // find sum
return a + b;
});
console.log(sum);
Using for loop and reduce()
var points = []; // initialize an array
for (var i = 1; i <= 10000; i++) {
points.push(i);
}
var sum = points.reduce(function(a, b) { // find sum
return a + b;
});
console.log(sum);
Also you can do the addition and array creation in single for loop
var points = [], // initialize an array
sum = 0;
for (var i = 1; i <= 10000; i++) {
points.push(i); // pushing value to array
sum += i; // summation
}
console.log(sum, points);
var result = 0;
for(var i = 0; i < points.length; i++) {
result += points[i];
}
Function that takes an array of any length and returns the sum:
function sumArray(arrayToSum){
var result = 0;
for(var i = 0; i < arrayToSum.length; i++) {
result += points[i];
}
return result;
}
function arraysum(arraylength) {
var arraysum = 0;
var array1 = new Array();
for(i=1; i<=arraylength; i++) {
array1.push(i);
}
for(i = 0; i< array1.length; i++) {
arraysum += array1[i];
}
return arraysum;
}
Now when you call the function
arraysum(x)
pass the function some variable or integer for example 1, 15, or 10000.
A very elegant and compact solution is to use reduce. It accumulates the array values to reduce it to a single value by applying each value and a start value to a given function, whose return value is used as the start value for the next iteration:
function sum (a, b) {
return a + b;
}
console.log(points.reduce(sum, 0));
If you need to support older browser (e.g. IE 8) you can use a Polyfill.
If you need to create the list of numbers as well, you can create it with
var points = Array.apply(0, Array(10000))
.map(function (current, index) {
return index + 1;
});
It creates an array of 10000 elements and assigns each element it's index + 1.
I have an Array a = [0,1,2,3,4,5,6]
and I want to subset with 3 elements so the result becomes this:
[0,1,2],[1,2,3],[2,3,4],[3,4,5],[4,5,6]
I tried using this script that I found :
Array.prototype.combinate = function( iItems, aIn ) {
if (!aIn) {
var aIn = new Array();
this.combinate.aResult = new Array();
}
for(var i = 0; i < this.length; i++) {
var a = aIn.concat(this[i]);
var aRest = this.concat(); // Concat with nothing to create copy
aRest.splice(0, i + 1);
if(iItems && iItems - 1 <= aRest.length) {
aRest.combinate(iItems - 1, a);
if(iItems == 1) this.combinate.aResult.push(a);
}
}
return this.combinate.aResult;
}
But this gives all possible subset (and become easily slow when the list becomes big and the search subset is small) - I only need the "sequential" subset like shown above - so like [1,2,3] is ok - but not [1,2,4] ..
Any bright people out there who knows how to do this in JavaScript ..?
Assuming the array in question does not need to be sorted in some way first, I would do it this way:
function combinate(arr) {
var results = [];
if (arr.length >= 3) {
for (var i = 0; i < arr.length - 2; i++) {
var slice = arr.slice(i, i + 3);
results.push(slice);
}
}
return results;
}
As an additional note, I would recommend against adding something like this as a method to the Array prototype. Nothing stopping you from doing so if you need to for some reason, but I would avoid it.
Try this:
for (var i = 0; i < arr.length - 2; i++) {
var combination = new Array(arr[i], arr[i + 1], arr[i + 2]);
// or this
// var combination = [arr[i], arr[i + 1], arr[i + 2]];
// do something with the new array ??
}