Why does this loop terminate partway through? - javascript

I'm trying to write a program to find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters.
The range will be an array of two numbers that will not necessarily be in numerical order.
For example, for 1 and 3 - find the smallest common multiple of both 1 and 3 that is evenly divisible by all numbers between 1 and 3.
Why does the loop stop at i = 510,000 (or something close to that) instead of 7,000,000, as I set it?
I also have a screenshot with the output:
function smallestCommons(arr) {
var start;
var finish;
var something;
if(arr[0] < arr[1]){start = arr[0]; finish = arr[1];}else{
start = arr[1]; finish = arr[0];
}
for(var i = finish;i <= 7000000;i++){
var boolea = true;
for(var j = start;j <= finish;j++){
if(i % j !== 0){boolea = false;break;} // 2 % 1
}
if(boolea)return i;
something = i;
}
console.log("final i = " + i);
return 0;
}

Try to add this at the beginning of your loop
// noprotect
it must be that jsbin is forcing your code to exit from the loop. See source

Related

How to get numbers of variants numerical combinations in javascript?

I need to implement a function that accepts two parameters - the number of 0 and the number of 1 and determine how many ways to place these 0 and 1 so that there are no two zeros in a row.
For example, I need to find all methods of placing two 0 and two 1.
There are six possible ways to place them: 0011, 0101, 0110, 1001, 1010, 1100.
In three cases there are two zeros in a row: 0011, 1001 and 1100.
I subtract them from the total number and get three possible ways: 0101, 0110 and 1010. So the answer is 3.
First, I'm trying to write script to recognize which cases I need
let arr = ["1100","1010","1001","0011","0101","0110"]
let result = [];
for (let i = 0; i < arr.length; i++){
let expVal = arr[i];
for (let p = 0; p < expVal.length; p++){
if (expVal[p] === expVal[p++] || expVal[p] === "0"){
result.push(expVal)
}
}
}
console.log(result);
It's does not work. I don't know how to fix it.
And I don't understand what I need to do later
The problem you are solving is equivalent to the Fibonacci sequence.
filter for includes '00'
recursive function x generates binary number strings using n0 zeroes, n1 ones. Works by branching to (add a zero, find combos for one less zero)'0'+x(n0-1,n1) and (add a one, find combos for one less 1)'1'+x(n0,n1-1).
let arr = ["1100","1010","1001","0011","0101","0110"]
const x = (n0,n1) =>
!(n0 === 0 || n1 === 0) ?
x(n0-1,n1).map(x=>'0'+x).concat(
x(n0,n1-1).map(x=>'1'+x))
: ['0'.repeat(n0)||'1'.repeat(n1)]
arr = x(2,2)
console.log(
x(2,2)
)
console.log(arr.filter(x=>x.includes('00')))
There are 2 issues with the code, as far as I can see:
You're incrementing p two times: once in the for definition, and once in the execution itself (p++). The second one should be replaced by p+1
Also, you're checking if the next character is equal to the current, OR the current character is 0. This should be AND.
let arr = ["1100","1010","1001","0011","0101","0110"]
let result = [];
for (let i = 0; i < arr.length; i++){
let expVal = arr[i];
for (let p = 0; p < expVal.length; p++){
if (expVal[p] === expVal[p+1] && expVal[p] === "0"){
result.push(expVal)
}
}
}
console.log(result);
Changing those two things fixes it.

Minimum number of swaps to sort an array

I need to do something like this: Let's say I have an array:
[3, 4, 1, 2]
I need to swap 3 and 4, and 1 and 2, so my array looks like [4, 3, 2, 1]. Now, I can just do the sort(). Here I need to count how many iterations I need, to change the initial array to the final output. Example:
// I can sort one pair per iteration
let array = [3, 4, 1, 2, 5]
let counter = 0;
//swap 3 and 4
counter++;
// swap 1 and 2
counter++;
// 5 goes to first place
counter++
// now counter = 3 <-- what I need
EDIT: Here is what I tried. doesn't work always tho... it is from this question: Bubble sort algorithm JavaScript
let counter = 0;
let swapped;
do {
swapped = false;
for (var i = 0; i < array.length - 1; i++) {
if (array[i] < array[i + 1]) {
const temp = array[i];
array[i] = array[i + 1];
array[i + 1] = temp;
swapped = true;
counter++;
}
}
} while (swapped);
EDIT: It is not correct all the time because I can swap places from last to first, for example. Look at the example code above, it is edited now.
This is most optimal code I have tried so far, also the code is accepted as optimal
answer by hackerrank :
function minimumSwaps(arr) {
var arrLength = arr.length;
// create two new Arrays
// one record value and key separately
// second to keep visited node count (default set false to all)
var newArr = [];
var newArrVisited = [];
for (let i = 0; i < arrLength; i++) {
newArr[i]= [];
newArr[i].value = arr[i];
newArr[i].key = i;
newArrVisited[i] = false;
}
// sort new array by value
newArr.sort(function (a, b) {
return a.value - b.value;
})
var swp = 0;
for (let i = 0; i < arrLength; i++) {
// check if already visited or swapped
if (newArr[i].key == i || newArrVisited[i]) {
continue;
}
var cycle = 0;
var j = i;
while (!newArrVisited[j]) {
// mark as visited
newArrVisited[j] = true;
j = newArr[j].key; //assign next key
cycle++;
}
if (cycle > 0) {
swp += (cycle > 1) ? cycle - 1 : cycle;
}
}
return swp;
}
reference
//You are given an unordered array consisting of consecutive integers [1, 2, 3, ..., n] without any duplicates.
//still not the best
function minimumSwaps(arr) {
let count = 0;
for(let i =0; i< arr.length; i++){
if(arr[i]!=i+1){
let temp = arr[i];
arr[arr.indexOf(i+1)] =temp;
arr[i] = i+1;
count =count+1;
}
}
return count;
}
I assume there are two reasons you're wanting to measure how many iterations a sort takes. So I will supply you with some theory (if the mathematics is too dense, don't worry about it), then some practical application.
There are many sort algorithms, some of them have a predicable number of iterations based on the number of items you are sorting, some of them are luck of the draw simply based on the order of the items to be sorted and which item how you select what is called a pivot. So if optimisation is very important to you, then you'll want to select the right algorithm for the purpose of the sort algorithm. Otherwise go for a general purpose algorithm.
Here are most popular sorting algorithms for the purpose of learning, and each of them have least, worst and average running-cases. Heapsort, Radix and binary-sort are worth looking at if this is more than just an theoretical/learning exercise.
Quicksort
Worst Case: Θ(n 2)
Best case: Θ(n lg n)
Average case: Θ(n lg n)
Here is a Quicksort implementation by Charles Stover
Merge sort
Worst case: Θ(n lg n)
Best case: Θ(n lg n)
Average Case: Θ(n lg n)
(note they're all the same)
Here is a merge sort implementation by Alex Kondov
Insertion sort
Worst case: Θ(n2)
Best case: Θ(n)
Average case:Θ(n2)
(Note that its worst and average case are the same, but its best case is the best of any algorithm)
Here is an insertion sort implementation by Kyle Jensen
Selection sort
Worst case: Θ(n2)
Best case: Θ(n2)
Average case: Θ(n2)
(note they're all the same, like a merge sort).
Here is a selection sort algorithm written by #dbdavid updated by myself for ES6
You can quite easily add an iterator variable to any of these examples to count the number of swaps they make, and play around with them to see which algorithms work best in which circumstance.
If there's a very good chance the items will already be well sorted, insertion sort is your best choice. If you have absolutely no idea, of the four basic sorting algorithms quicksort is your best choice.
function minimumSwaps(arr) {
var counter = 0;
for (var i = arr.length; i > 0; i--) {
var minval = Math.min(...arr); console.log("before", arr);
var minIndex = arr.indexOf(minval);
if (minval != = arr[0]) {
var temp = arr[0];
arr[0] = arr[minIndex];
arr[minIndex] = temp; console.log("after", arr);
arr.splice(0, 1);
counter++;
}
else {
arr.splice(0, 1); console.log("in else case")
}
} return counter;
}
This is how I call my swap function:
minimumSwaps([3, 7, 6, 9, 1, 8, 4, 10, 2, 5]);
It works with Selection Sort. Logic is as follows:
Loop through the array length
Find the minimum element in the array and then swap with the First element in the array, if the 0th Index doesn't have the minimum value founded out.
Now remove the first element.
If step 2 is not present, remove the first element(which is the minimum value present already)
increase counter when we swap the values.
Return the counter value after the for Loop.
It works for all values.
However, it fails due to a timeout for values around 50,000.
The solution to this problem is not very intuitive unless you are already somewhat familiar with computer science or real math wiz, but it all comes down to the number of inversions and the resulting cycles
If you are new to computer science I recommend the following resources to supplement this solution:
GeeksforGeeks Article
Informal Proof Explanation
Graph Theory Explanation
If we define an inversion as:
arr[i]>arr[j]
where "i" is the current index and "j" is the following index --
if there are no inversions the array is already in order and requires no sorting.
For Example:
[1,2,3,4,5]
So the number of swaps is related to the number of inversions, but not directly because each inversion can lead to a series of swaps (as opposed to a singular swap EX: [3,1,2]).
So if one consider's the following array:
[4,5,2,1,3,6,10,9,7,8]
This array is composed of three cycles.
Cycle One- 4,1,3 (Two Swaps)
Cycle Two- 5,2 (One Swap)
Cycle Three- 6 (0 Swaps)
Cycle Four- 10,9,7,8 (3 Swaps)
Now here's where the CS and Math magic really kicks in: each cycle will only require one pass through to properly sort it, and this is always going to be true.
So another way to say this would be-- the minimum number of swaps to sort any cycle is the number of element in that cycle minus one, or more explicitly:
minimum swaps = (cycle length - 1)
So if we sum the minimum swaps from each cycle, that sum will equal the minimum number of swaps for the original array.
Here is my attempt to explain WHY this algorithm works:
If we consider that any sequential set of numbers is just a section of a number line, then any set starting at zero should be equal to its own index should the set be expressed as a Javascript array. This idea becomes the criteria to programmatically determined if in element is already in the correct position based on its own value.
If the current value is not equal to its own index then the program should detect a cycle start and recording its length. Once the while loop reaches the the original value in the cycle it will add the minimum number of swaps in the cycle to a counter variable.
Anyway here is my code-- it is very verbose but should work:
export const minimumSwaps = (arr) => {
//This function returns the lowest value
//from the provided array.
//If one subtracts this value the from
//any value in the array it should equal
//that value's index.
const shift = (function findLowest(arr){
let lowest=arr[0];
arr.forEach((val,i)=>{
if(val<lowest){
lowest=val;
}
})
return lowest;
})(arr);
//Declare a counter variable
//to keep track of the swaps.
let swaps = 0;
//This function returns an array equal
//in size to the original array provided.
//However, this array is composed of
//boolean values with a value of false.
const visited = (function boolArray(n){
const arr=[];
for(let i = 0; i<n;i++){
arr.push(false);
}
return arr;
})(arr.length);
//Iterate through each element of the
//of the provided array.
arr.forEach((val, i) => {
//If the current value being assessed minus
//the lowest value in the original array
//is not equal to the current loop index,
//or, if the corresponding index in
//the visited array is equal to true,
//then the value is already sorted
if (val - shift === i || visited[i]) return;
//Declare a counter variable to record
//cycle length.
let cycleLength = 0;
//Declare a variable for to use for the
//while loop below, one should start with
//the current loop index
let x = i;
//While the corresponding value in the
//corresponding index in the visited array
//is equal to false, then we
while (!visited[x]) {
//Set the value of the current
//corresponding index to true
visited[x] = true;
//Reset the x iteration variable to
//the next potential value in the cycle
x = arr[x] - shift;
//Add one to the cycle length variable
cycleLength++;
};
//Add the minimum number of swaps to
//the swaps counter variable, which
//is equal to the cycle length minus one
swaps += cycleLength - 1;
});
return swaps
}
This solution is simple and fast.
function minimumSwaps(arr) {
let minSwaps = 0;
for (let i = 0; i < arr.length; i++) {
// at this position what is the right number to be here
// for example at position 0 should be 1
// add 1 to i if array starts with 1 (1->n)
const right = i+1;
// is current position does not have the right number
if (arr[i] !== right) {
// find the index of the right number in the array
// only look from the current position up passing i to indexOf
const rightIdx = arr.indexOf(right, i);
// replace the other position with this position value
arr[rightIdx] = arr[i];
// replace this position with the right number
arr[i] = right;
// increment the swap count since a swap was done
++minSwaps;
}
}
return minSwaps;
}
Here is my solution, but it timeouts 3 test cases with very large inputs. With smaller inputs, it works and does not terminate due to timeout.
function minimumSwaps(arr) {
let swaps = 0;
for (let i = 0; i < arr.length; i++) {
if (arr[i] === i + 1) continue;
arr.splice(i, 1, arr.splice(arr.indexOf(i + 1), 1, arr[i])[0]); //swap
swaps++;
}
return swaps;
}
I'm learning how to make it more performant, any help is welcome.
This is my solution to the Main Swaps 2 problem in JavaScript. It passed all the test cases. I hope someone finds it useful.
//this function calls the mainSwaps function..
function minimumSwaps(arr){
let swaps = 0;
for (var i = 0; i < arr.length; i++){
var current = arr[i];
var targetIndex = i + 1;
if (current != targetIndex){
swaps += mainSwaps(arr, i);
}
}
return swaps;
}
//this function is called by the minimumSwaps function
function mainSwaps(arr, index){
let swapCount = 0;
let currentElement = arr[index];
let targetIndex = currentElement - 1;
let targetElement = arr[currentElement - 1];
while (currentElement != targetElement){
//swap the elements
arr[index] = targetElement;
arr[currentElement - 1] = currentElement;
//increase the swapcount
swapCount++;
//store the currentElement, targetElement with their new values..
currentElement = arr[index];
targetElement = arr[currentElement - 1];
}
return swapCount;
}
var myarray = [2,3,4,1,5];
var result = console.log(minimumSwaps(myarray));
you can also do it with a map. But its O(nlogn)
const minSwaps = (arr) =>{
let arrSorted = [...arr].sort((a,b)=>a-b);
let indexMap = new Map();
// fill the indexes
for(let i=0; i<arr.length; i++){
indexMap.set(arr[i],i);
}
let count = 0;
for(let i=0; i<arrSorted.length;i++){
if(arr[i] != arrSorted[i]){
count++;
// swap the index
let newIdx = indexMap.get(arrSorted[i]);
indexMap.set(arr[i],newIdx);
indexMap.set(arrSorted[i],i);
// sawp the values
[arr[i],arr[newIdx]] =[arr[newIdx],arr[i]];
}
}
return count;
}

Codility Peak JavaScript Implementation

I am working on the Codility Peak problem:
Divide an array into the maximum number of same-sized blocks, each of which should contain an index P such that A[P - 1] < A[P] > A[P + 1].
My own solution is provided below, but it only scores 45%. So my question is:
How can I still improve my solution?
The code snippet seems to be long, since I added some extra comments to make myself clearer:
function solution(A) {
var storage = [], counter = 0;
// 1. So first I used a loop to find all the peaks
// and stored them all into an array called storage
for(var i = 1; i < A.length - 1; i++) {
if (A[i] > A[i-1] && A[i] > A[i+1]) {
storage.push(i);
}
}
// 2. Go and write the function canBeSeparatedInto
// 3. Use the for loop to check the counter
for(var j = 1; j < A.length; j++) {
if (canBeSeparatedInto(j, A, storage)) {
counter = j;
}
}
return counter;
}
/* this function tells if it is possible to divide the given array into given parts
* we will be passing our function with parameters:
* #param parts[number]: number of parts that we intend to divide the array into
* #param array[array]: the original array
* #param peaks[array]: an storage array that store all the index of the peaks
* #return [boolean]: true if the given array can be divided into given parts
*/
function canBeSeparatedInto(parts, array, peaks) {
var i = 1, result = false;
var blockSize = array.length / parts;
peaks.forEach(function(elem) {
// test to see if there is an element in the array belongs to the ith part
if ((elem+1)/blockSize <= i && (elem+1)/blockSize> i-1) {
i++;
}
});
// set the result to true if there are indeed peaks for every parts
if (i > parts) {
result = true;
}
return result;
}
The main problem with my code is that it does not pass the performance test. Could you give me some hint on that?
I would suggest this algorithm:
Sort the peeks by the distance they have with their predecessor. To do that, it might be more intuitive to identify "valleys", i.e. maximised ranges without peeks, and sort those by their size in descending order
Identify the divisors of the array length, as the solution must be one of those. For example, it is a waste of time to test for solutions when the array length is prime: in that case the answer can only be 1 (or zero if it has no peeks).
Try each of the divisors in ascending order (representing the size of array chunks), and see if for each valley such a split would bring one of the chunks completely inside that valley, i.e. it would not contain a peek: in that case reject that size as a solution, and try the next size.
Implementation with interactive input of the array:
"use strict";
// Helper function to collect the integer divisors of a given n
function divisors(n) {
var factors = [],
factors2 = [],
sq = Math.sqrt(n);
for (var i = 1; i <= sq; i++) {
if (n % i === 0) {
factors.push(n / i);
// Save time by storing complementary factor as well
factors2.push(i);
}
}
// Eliminate possible duplicate when n is a square
if (factors[factors.length-1] === factors2[factors2.length-1]) factors.pop();
// Return them sorted in descending order, so smallest is at end
return factors.concat(factors2.reverse());
}
function solution(A) {
var valleys = [],
start = 0,
size, sizes, i;
// Collect the maximum ranges that have no peeks
for (i = 1; i < A.length - 1; i++) {
if (A[i] > A[i-1] && A[i] > A[i+1]) {
valleys.push({
start,
end: i,
size: i - start,
});
start = i + 1;
}
}
// Add final valley
valleys.push({
start,
end: A.length,
size: A.length - start
});
if (valleys.length === 1) return 0; // no peeks = no solution
// Sort the valleys by descending size
// to improve the rest of the algorithm's performance
valleys.sort( (a, b) => b.size - a.size );
// Collect factors of n, as all chunks must have same, integer size
sizes = divisors(A.length)
// For each valley, require that a solution must not
// generate a chunk that falls completely inside it
do {
size = sizes.pop(); // attempted solution (starting with small size)
for (i = 0;
i < valleys.length &&
// chunk must not fit entirely inside this valley
Math.ceil(valleys[i].start / size) * size + size > valleys[i].end; i++) {
}
} while (i < valleys.length); // keep going until all valleys pass the test
// Return the number of chunks
return A.length / size;
}
// Helper function: chops up a given array into an
// array of sub arrays, which all have given size,
// except maybe last one, which could be smaller.
function chunk(arr, size) {
var chunks = [];
for (var i = 0; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size));
}
return chunks;
}
// I/O management
inp.oninput = function () {
// Get input as an array of positive integers (ignore non-digits)
if (!this.value) return;
var arr = this.value.match(/\d+/g).map(v => +v);
var parts = solution(arr);
// Output the array, chopped up into its parts:
outCount.textContent = parts;
outChunks.textContent = chunk(arr, arr.length / parts).join('\n');
}
Array (positive integers, any separator): <input id="inp" style="width:100%">
Chunks: <span id="outCount"></span>
<pre id="outChunks"></pre>
When checking whether array can be splitted into K parts, you will in worst case (array of [1,2,1,2,1,...]) do N/2 checks (since you are looking at every peak).
This can be done in K steps, by using clever datastructures:
Represent peaks as an binary array (0 - no peak, 1 - peak). Calculate prefix sums over that. If you want to check if block contains a peak, just compare prefix sums at the start and end of the block.
And also you have small other problem there. You should not check number of block which does not divide the size of the array.

Efficiently find every combination of assigning smaller bins to larger bins

Let's say I have 7 small bins, each bin has the following number of marbles in it:
var smallBins = [1, 5, 10, 20, 30, 4, 10];
I assign these small bins to 2 large bins, each with the following maximum capacity:
var largeBins = [40, 50];
I want to find EVERY combination of how the small bins can be distributed across the big bins without exceeding capacity (eg put small bins #4,#5 in large bin #2, the rest in #1).
Constraints:
Each small bin must be assigned to a large bin.
A large bin can be left empty
This problem is easy to solve in O(n^m) O(2^n) time (see below): just try every combination and if capacity is not exceeded, save the solution. I'd like something faster, that can handle a variable number of bins. What obscure graph theory algorithm can I use to reduce the search space?
//Brute force
var smallBins = [1, 5, 10, 20, 30, 4, 10];
var largeBins = [40, 50];
function getLegitCombos(smallBins, largeBins) {
var legitCombos = [];
var assignmentArr = new Uint32Array(smallBins.length);
var i = smallBins.length-1;
while (true) {
var isValid = validate(assignmentArr, smallBins, largeBins);
if (isValid) legitCombos.push(new Uint32Array(assignmentArr));
var allDone = increment(assignmentArr, largeBins.length,i);
if (allDone === true) break;
}
return legitCombos;
}
function increment(assignmentArr, max, i) {
while (i >= 0) {
if (++assignmentArr[i] >= max) {
assignmentArr[i] = 0;
i--;
} else {
return i;
}
}
return true;
}
function validate(assignmentArr, smallBins, largeBins) {
var totals = new Uint32Array(largeBins.length);
for (var i = 0; i < smallBins.length; i++) {
var assignedBin = assignmentArr[i];
totals[assignedBin] += smallBins[i];
if (totals[assignedBin] > largeBins[assignedBin]) {
return false;
}
}
return true;
}
getLegitCombos(smallBins, largeBins);
Here's my cumbersome recursive attempt to avoid duplicates and exit early from too large sums. The function assumes duplicate elements as well as bin sizes are presented grouped and counted in the input. Rather than place each element in each bin, each element is placed in only one of duplicate bins; and each element with duplicates is partitioned distinctly.
For example, in my results, the combination, [[[1,10,20]],[[4,5,10,30]]] appears once; while in the SAS example in Leo's answer, twice: once as IN[1]={1,3,4} IN[2]={2,5,6,7} and again as IN[1]={1,4,7} IN[2]={2,3,5,6}.
Can't vouch for efficiency or smooth-running, however, as it is hardly tested. Perhaps stacking the calls rather than recursing could weigh lighter on the browser.
JavaScript code:
function f (as,bs){
// i is the current element index, c its count;
// l is the lower-bound index of partitioned element
function _f(i,c,l,sums,res){
for (var j=l; j<sums.length; j++){
// find next available duplicate bin to place the element in
var k=0;
while (sums[j][k] + as[i][0] > bs[j][0]){
k++;
}
// a place for the element was found
if (sums[j][k] !== undefined){
var temp = JSON.stringify(sums),
_sums = JSON.parse(temp);
_sums[j][k] += as[i][0];
temp = JSON.stringify(res);
var _res = JSON.parse(temp);
_res[j][k].push(as[i][0]);
// all elements were placed
if (i == as.length - 1 && c == 1){
result.push(_res);
return;
// duplicate elements were partitioned, continue to next element
} else if (c == 1){
_f(i + 1,as[i + 1][1],0,_sums,_res);
// otherwise, continue partitioning the same element with duplicates
} else {
_f(i,c - 1,j,_sums,_res);
}
}
}
}
// initiate variables for the recursion
var sums = [],
res = []
result = [];
for (var i=0; i<bs.length; i++){
sums[i] = [];
res[i] = [];
for (var j=0; j<bs[i][1]; j++){
sums[i][j] = 0;
res[i][j] = [];
}
}
_f(0,as[0][1],0,sums,res);
return result;
}
Output:
console.log(JSON.stringify(f([[1,1],[4,1],[5,1],[10,2],[20,1],[30,1]], [[40,1],[50,1]])));
/*
[[[[1,4,5,10,10]],[[20,30]]],[[[1,4,5,10,20]],[[10,30]]],[[[1,4,5,20]],[[10,10,30]]]
,[[[1,4,5,30]],[[10,10,20]]],[[[1,4,10,20]],[[5,10,30]]],[[[1,4,30]],[[5,10,10,20]]]
,[[[1,5,10,20]],[[4,10,30]]],[[[1,5,30]],[[4,10,10,20]]],[[[1,10,20]],[[4,5,10,30]]]
,[[[1,30]],[[4,5,10,10,20]]],[[[4,5,10,20]],[[1,10,30]]],[[[4,5,30]],[[1,10,10,20]]]
,[[[4,10,20]],[[1,5,10,30]]],[[[4,30]],[[1,5,10,10,20]]],[[[5,10,20]],[[1,4,10,30]]]
,[[[5,30]],[[1,4,10,10,20]]],[[[10,10,20]],[[1,4,5,30]]],[[[10,20]],[[1,4,5,10,30]]]
,[[[10,30]],[[1,4,5,10,20]]],[[[30]],[[1,4,5,10,10,20]]]]
*/
console.log(JSON.stringify(f([[1,1],[4,1],[5,1],[10,2],[20,1],[30,1]], [[20,2],[50,1]])));
/*
[[[[1,4,5,10],[10]],[[20,30]]],[[[1,4,5,10],[20]],[[10,30]]],[[[1,4,5],[20]],[[10,10,30]]]
,[[[1,4,10],[20]],[[5,10,30]]],[[[1,5,10],[20]],[[4,10,30]]],[[[1,10],[20]],[[4,5,10,30]]]
,[[[4,5,10],[20]],[[1,10,30]]],[[[4,10],[20]],[[1,5,10,30]]],[[[5,10],[20]],[[1,4,10,30]]]
,[[[10,10],[20]],[[1,4,5,30]]],[[[10],[20]],[[1,4,5,10,30]]]]
*/
Here's a second, simpler version that only attempts to terminate the thread when an element cannot be placed:
function f (as,bs){
var stack = [],
sums = [],
res = []
result = [];
for (var i=0; i<bs.length; i++){
res[i] = [];
sums[i] = 0;
}
stack.push([0,sums,res]);
while (stack[0] !== undefined){
var params = stack.pop(),
i = params[0],
sums = params[1],
res = params[2];
for (var j=0; j<sums.length; j++){
if (sums[j] + as[i] <= bs[j]){
var _sums = sums.slice();
_sums[j] += as[i];
var temp = JSON.stringify(res);
var _res = JSON.parse(temp);
_res[j].push(i);
if (i == as.length - 1){
result.push(_res);
} else {
stack.push([i + 1,_sums,_res]);
}
}
}
}
return result;
}
Output:
var r = f([1,5,10,20,30,4,10,3,4,5,1,1,2],[40,50,30]);
console.log(r.length)
console.log(JSON.stringify(f([1,4,5,10,10,20,30], [40,50])));
162137
[[[30],[1,4,5,10,10,20]],[[10,30],[1,4,5,10,20]],[[10,20],[1,4,5,10,30]]
,[[10,30],[1,4,5,10,20]],[[10,20],[1,4,5,10,30]],[[10,10,20],[1,4,5,30]]
,[[5,30],[1,4,10,10,20]],[[5,10,20],[1,4,10,30]],[[5,10,20],[1,4,10,30]]
,[[4,30],[1,5,10,10,20]],[[4,10,20],[1,5,10,30]],[[4,10,20],[1,5,10,30]]
,[[4,5,30],[1,10,10,20]],[[4,5,10,20],[1,10,30]],[[4,5,10,20],[1,10,30]]
,[[1,30],[4,5,10,10,20]],[[1,10,20],[4,5,10,30]],[[1,10,20],[4,5,10,30]]
,[[1,5,30],[4,10,10,20]],[[1,5,10,20],[4,10,30]],[[1,5,10,20],[4,10,30]]
,[[1,4,30],[5,10,10,20]],[[1,4,10,20],[5,10,30]],[[1,4,10,20],[5,10,30]]
,[[1,4,5,30],[10,10,20]],[[1,4,5,20],[10,10,30]],[[1,4,5,10,20],[10,30]]
,[[1,4,5,10,20],[10,30]],[[1,4,5,10,10],[20,30]]]
This problem is seen often enough that most Constraint Logic Programming systems include a predicate to model it explicitly. In OPTMODEL and CLP, we call it pack:
proc optmodel;
set SMALL init 1 .. 7, LARGE init 1 .. 2;
num size {SMALL} init [1 5 10 20 30 4 10];
num capacity{LARGE} init [40 50];
var WhichBin {i in SMALL} integer >= 1 <= card(LARGE);
var SpaceUsed{i in LARGE} integer >= 0 <= capacity[i];
con pack( WhichBin, size, SpaceUsed );
solve with clp / findall;
num soli;
set IN{li in LARGE} = {si in SMALL: WhichBin[si].sol[soli] = li};
do soli = 1 .. _nsol_;
put IN[*]=;
end;
quit;
This code produces all the solutions in 0.06 seconds on my laptop:
IN[1]={1,2,3,4,6} IN[2]={5,7}
IN[1]={1,2,3,4} IN[2]={5,6,7}
IN[1]={1,2,3,6,7} IN[2]={4,5}
IN[1]={1,2,5,6} IN[2]={3,4,7}
IN[1]={1,2,5} IN[2]={3,4,6,7}
IN[1]={1,2,4,6,7} IN[2]={3,5}
IN[1]={1,2,4,7} IN[2]={3,5,6}
IN[1]={1,2,4,6} IN[2]={3,5,7}
IN[1]={1,3,4,6} IN[2]={2,5,7}
IN[1]={1,3,4} IN[2]={2,5,6,7}
IN[1]={1,5,6} IN[2]={2,3,4,7}
IN[1]={1,5} IN[2]={2,3,4,6,7}
IN[1]={1,4,6,7} IN[2]={2,3,5}
IN[1]={1,4,7} IN[2]={2,3,5,6}
IN[1]={2,3,4,6} IN[2]={1,5,7}
IN[1]={2,3,4} IN[2]={1,5,6,7}
IN[1]={2,5,6} IN[2]={1,3,4,7}
IN[1]={2,5} IN[2]={1,3,4,6,7}
IN[1]={2,4,6,7} IN[2]={1,3,5}
IN[1]={2,4,7} IN[2]={1,3,5,6}
IN[1]={3,5} IN[2]={1,2,4,6,7}
IN[1]={3,4,7} IN[2]={1,2,5,6}
IN[1]={3,4,6} IN[2]={1,2,5,7}
IN[1]={3,4} IN[2]={1,2,5,6,7}
IN[1]={5,7} IN[2]={1,2,3,4,6}
IN[1]={5,6} IN[2]={1,2,3,4,7}
IN[1]={5} IN[2]={1,2,3,4,6,7}
IN[1]={4,6,7} IN[2]={1,2,3,5}
IN[1]={4,7} IN[2]={1,2,3,5,6}
Just change the first 3 lines to solve for other instances. However, as others have pointed out, this problem is NP-Hard. So it can switch from very fast to very slow suddenly. You could also solve the version where not every small item needs to be assigned to a large bin by creating a dummy large bin with enough capacity to fit the entire collection of small items.
As you can see from the "Details" section in the manual, the algorithms that solve practical problems quickly are not simple, and their implementation details make a big difference. I am unaware of any CLP libraries written in Javascript. Your best bet may be to wrap CLP in a web service and invoke that service from your Javascript code.

Calculating standard deviation not executing loop

I've just started learning coding on code academy and I'm really new to this.
I'm trying to make this program ask the user for values which it adds to an array from which it calculates the sample standard deviation.
// This array stores the values needed
var figures;
getStandardDeviation = function() {
// I need at least two figures for a standard deviation
figures[0] = prompt("Enter a number:");
figures[1] = prompt("Enter a number:");
// Checks whether user wishes to add more values to the array
var confirm = prompt("Would you like to add another? (Y or N)").toUpperCase();
// I can't figure out why the following if statement is not executed
// It checks whether the user wishes to add more values and adds them to the array
// If not it breaks the for loop
if (confirm === "Y"){
for ( i = 0; i === 100; i++){
figures[i + 2] = prompt("Enter a number:");
confirm = prompt("Would you like to add another figure? (Y or N)").toUpperCase();
if (confirm === "N"){
break;
}
}
}
// The rest of the code works fine from here onwards
var sumx = 0;
var n = figures.length;
for(var i = 0 ; i < n ; i++) {
sumx += figures[i];
}
console.log("Sum = " + sumx);
var sumXsq = 0;
for( i = 0 ; i < n ; i++) {
sumXsq += (figures[i] * figures[i]);
}
console.log("Sum x squared = " + sumXsq);
var sxx = (sumXsq - (sumx * sumx)/n);
console.log("Sxx = " + sxx);
var v = sxx/(n - 1);
console.log("Variance = " + v);
var standardDev = Math.sqrt(v);
console.log("Standard Deviation = " + standardDev);
};
getStandardDeviation();
The program is supposed to ask me if I want to add more values to the array, then when I confirm, it gives me a prompt to add more values.
Currently, when I execute the program I input the numbers 56 and 67. The code then asks me if I wish to add more values, I then confirm this. Instead of letting me add more values it ignores this and calculates the standard deviation with the first two values (56 and 67).
The output is:
Sum = 05667
Sum x squared = 7625
Sxx = -16049819.5
Variance = -16049819.5
Standard Deviation = NaN
for ( i = 0; i === 100; i++){[...]} means
Set i to 0
If it's not true that i === 100 (that is: if i is not 100), end the loop
Do whatever I put inside the {} braces, once
Do i++
Back to 2
As the initial value for i is 0 and not 100, the code inside the loop is never executed. If you want it to go from 0 to 99, it should be for ( i = 0; i < 100; i++).
You don't actually need a for loop, though. A while loop would be better. A loop like while (true){[...]} would run until it hit a break statement. As you wouldn't have the i in that case, you could use figures.push(parseFloat(prompt("Enter a number:"))) instead (you should use parseFloat, as per what Vincent Hogendoorn said) . push adds a new value at the end of an array, so it's exactly what you need. Something like:
if (confirm === "Y"){
while (true){
figures.push(parseFloat(prompt("Enter a number:")));
confirm = prompt("Would you like to add another figure? (Y or N)").toUpperCase();
if (confirm === "N"){
break;
}
}
}
You could also change it so it doesn't ask if you want to stop if you don't have at least two values. That way you would be able to leave out that first part:
figures[0] = prompt("Enter a number:");
figures[1] = prompt("Enter a number:");
indeed your figures variable isn't defined as an array, like #James Donnely says.
Keep in mind you also fill in strings, so if you want to add up values you have to convert them to values.
you can use something like parseFloat for this.
if you don't use it, you sum up strings. 3+4 will be 34 instead of 7.
Your figures variable isn't defined as an array. Because of this figure[1] = prompt(...) never gets hit and a TypeError is thrown on var n = figures.length;.
Change:
var figures;
To:
var figures = [];
JSFiddle demo.
You can then replace the for loop you're using after if (confirm === "Y") with a recursive function:
// Push a user input number into the figures array
figures.push(prompt("Enter a number:"));
// Function to add a new number and ask if we want to add more
function addNewNumber() {
// Push a new user input number into the figures array
figures.push(prompt("Enter a number:"));
// Ask if the user wants to add another number
if (confirm("Do you want to add another number?"))
// If they do, call this function again
addNewNumber();
}
// Trigger the function for the first time
addNewNumber();
JSFiddle demo with recursion.
function StandardDeviation(numbersArr) {
//--CALCULATE AVAREGE--
var total = 0;
for(var key in numbersArr)
total += numbersArr[key];
var meanVal = total / numbersArr.length;
//--CALCULATE AVAREGE--
//--CALCULATE STANDARD DEVIATION--
var SDprep = 0;
for(var key in numbersArr)
SDprep += Math.pow((parseFloat(numbersArr[key]) - meanVal),2);
var SDresult = Math.sqrt(SDprep/numbersArr.length);
//--CALCULATE STANDARD DEVIATION--
alert(SDresult);
}
var numbersArr = [10, 11, 12, 13, 14];
StandardDeviation(numbersArr);

Categories