simple elevator in javascript - javascript

I'm trying to code a solution to the following challenge question found on codewars.com:
There is a house with 4 levels. In that house there is an elevator. You can program this elevator to go up or down, depending on what button the user touches inside the elevator.
valid levels can be only these numbers: 0,1,2,3
valid buttons can be only these strings: '0','1','2','3'
possible return values are these numbers: -3,-2,-1,0,1,2,3
If the elevator is on the ground floor(0th level) and the user touches button '2' the elevator must go 2 levels up, so our function must return 2.
If the elevator is on the 3rd level and the user touches button '0' the elevator must go 3 levels down, so our function must return -3.
If the elevator is on the 2nd level, and the user touches button '2' the elevator must remain on the same level, so we return 0.
We cannot endanger the lives of our passengers, so if we get erronous inputs, our elevator must remain on the same level. So for example:
goto(2,'4') must return 0, because there is no button '4' in the elevator.
goto(4,'0') must return 0, because there is no level 4.
goto(3,undefined) must return 0.
goto(undefined,'2') must return 0.
goto([],'2') must return 0 because the type of the input level is array instead of a number.
goto(3,{}) must return 0 because the type of the input button is object instead of a string.
I can came up with the following code but I am failing about 40% of the test case. Can someone tell me where I am wrong with my logic:
function goto(level,button){
var arr = [0, 1, 2, 3];
var result = 0
for(var i = 0; i < arr.length; i++){
for(var j = 0; j < arr.length; j++){
if(level === arr[i] && button === arr[j]){
if(level < button){
result = level + button;
}else{
result = button - level;
}
}
}
}
return result;
}
I am refactored my code, but I am still failing 1 of 31 test cases with the following message given:
Expected: 0, instead got: 1
Refactored code:
function goto(level,button){
var valid = [0, 1, 2, 3];
button = Number(button);
if (typeof level === 'number' && typeof button === 'number') {
for(var i = 0; i < valid.length; i++){
for(var j = 0; j < valid.length; j++){
if(level === valid[i] && button === valid[j]){
return button - level;
}
}
}
}
return 0;
}

I suspect it is because level is a number, however button is a string. In javascript, because of type conversions :
3 - '2'; // return 1
3 + '2'; // return '32';
Use the function Number() to convert your buttons string to a number, and you will have the true add behavior that you want.

You should do data format check first and also make it too complicated in calculating the result.
It should work as below.
function goto(level,button){
var floors = [0, 1, 2, 3];
var level_num = parseInt(level);
var button_num = parseInt(button);
if (typeof floors[level_num] == 'undefined' || typeof floors[button_num] == 'undefined') {
return 0;
}
return button_num - level_num;
}

Related

Sort function that uses an integer array argument doesnt work

I'm a beginner trying to learn JS, I've got some basic knowledge.
I wrote a function to realize insertion sort on a given array (the array is passed on to the function as a parameter).
When I initialize the array and give it value, e.g,
sampleArray = [1,35,73,234,1,1,356];
and pass that to my function, it works perfectly.
however, if I try to pass on an array filled by user input - or an array that was merged out of two given arrays (my original assignment),
it doesn't work - no exceptions or errors, it just... doesn't sort as expected.
I've been racking my mind over this, maybe I don't know where to look?
function sortArray(arrT) {
for (let i = 1; i < arrT.length; i++){
var tempMax = arrT[i];
var j = i - 1;
while ((j >= 0) && (arrT[j] > tempMax)) {
console.log(arr1 + "\nj=" + j + " i=" + i);
arrT[j+1] = arrT[j];
j--;
}
arrT[j+1] = tempMax;
}
console.log("sorted array is (inside loop) :\n" +arrT);
return arrT;
}
for an array that was filled by a while loop of prompts such as
it's equal to the above sample array, the result is
1,1,1,234,35,356,73
for reference, though it's far from elegant, I'm using this to fill the array:
for (let i = 0, x = ""; x !== "x"; i++) {
x = prompt("press x to finish, enter to continue");
if (x == "x") { break }
arr1[i]=prompt("enter");
}
As per my understanding.
The mistake is here
Original Code:
for (let i = 0, x = ""; x !== "x"; i++) {
x = prompt("press x to finish, enter to continue");
if (x == "x") { break }
arr1[i]=prompt("enter");//do not use prompts while unnecessary. Just replace it with x;
}
Corrected One:
for (let i = 0, x = ""; x !== "x"; i++) {
x = prompt("press x to finish, enter to continue");
if (x == "x") { break }
/*
you can also improve your code by applying few checks
if(!isNaN(x)) continue; // --- to skip when input value isn't a number
*/
arr1[i]=x;
}
for (let i = 0, x = ""; x !== "x"; i++) {
x = prompt("press x to finish, enter to continue");
if (x == "x") { break }
arr1[i]=prompt("enter");
}
prompt actually returns a string, hence your input is an array of strings instead. You should use Number to ensure the provided value is numeric.
I would rewrite the above in this way:
// stores all the values.
var arr1 = [];
// Stores the current value.
var input;
do {
var _ = prompt("press x to finish, enter to continue"); // <-- not sure why you're doing that every time, I would suggest you to move it outside of the loop.
input = prompt("enter");
var n = Number(input);
if (!isNaN(n)) arr1.push(n); // <-- checks whether the provided value is actually numeric and a valid number. If it is, the value is added to the collection.
}
while (input !== 'x');
console.log(arr1);
I would suggest you to move the first prompt outside of the loop, but since you did it in your code, I suspect there is a reason for that, though I don't get it.
In any case, the above sample will check whether the value passed is valid; if it is, it push the item to the collection, otherwise it continues until 'x' is met.

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;
}

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.

How to display the updated element in javascript array

I have a javascript issue. Suppose I have an input box that the user can enter the values and I store them in an array and display the array. Values like:
apple 8, orange 4, pear 10, orange 3.
What I want to do is to show the latest updated added value so when the user wants to see the values they see which is (all values in the array plus the latest updated value) so I dont want to show orange 4! I want to show orange 3 instead.
apple 8, pear 10, orange 3. //numbers are quantity of fruits that I randomly set
So the orange with the quantity of 4 is replaced y the orange with quantity of 3. This is my code for creating array, I think I should use key value store or hash instead, to display the last updated value, can you give me any hint? Thanks
this.fruitArray.push(inputData);
this.fruitArray = this.removeDuplicate(this.fruitArray);
if(inputData !== "" ){
$('#displayBox').html(this.fruitArray);
}
removeDuplicate: function(Arr){
var cur, found;
for (i = Arr.length - 1; i >= 0; i--) {
cur = Arr[i];
found = false;
for (j = i - 1; !found && j >= 0; j--) {
if (cur === Arr[j]) {
if (i !== j) {
Arr.splice(i, 1);
}
found = true;
}
}
}
return Arr;
},
if you just want access to the last element of an array, you can do it like this:
var lastElement = myArray[myArray.length-1]
in your case:
$('#displayBox').html(fruitArray[fruitArray.length -1]);
example: FIDDLE
--EDIT---------------------------
Still not sure of what you try to achieve, but could you just store the last fruit update in an other variable ?
var fruitArray = [];
var lastFruitUpdate = "";
....
if(inputData !== "" ){
lastFruitUpdate = inputData;
if(fruitArray[inputData] != undefined){
fruitArray[inputData]++;
}else{
fruitArray[inputData] = 1;
}
$('#displayBox').html(lastFruitUpdate+"( "+fruitArray[lastFruitUpdate]+")");
}
example: FIDDLE
If you want last element of array which is just added into array, then use below statement.
this.fruitArray.push[this.fruitArray.length-1]

Testing if an array contains any one of eight 3-key values -- Tic Tac Toe game

I'm working on a simple Tic Tac Toe game in Javascript. Right now, to check for a winner, I have a function that first gets whose turn it is and then finds wherever they have an X or an O on the board. The spaces they have are numbered (1-8) and added to an array. So far so good.
Now I'm trying to compare another array, the array with all of the winning combinations:
var winningCombinations = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]];
with a test array, that should come up a winner as it contains 2, 5, and 8.
Source of my test:
<script>
var test = [2,4,5,8]
var winningCombinations = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]];
for(var x=0; x<winningCombinations.length; x++) {
if (winningCombinations[x].indexOf(test) > -1) {
alert("Win!");
} else {
alert ("No win.");
}
}
</script>
I think right now it's only testing for [2,4,5,8] as an entire value--not for an instance of the individual numbers inside. This is where I'm stumped. How can I check to see if the test array, in any order, matches any of the winningCombinations values?
Try this:
var test = [2,4,5,8]
var winningCombinations = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]];
var combLength = 0;
for (var i in winningCombinations) {
combLength = winningCombinations.length;
for (var j in winningCombinations[i]) {
if (-1 == test.indexOf(winningCombinations[i][j])) {
break;
}
}
if (combLength - 1 == j) {
alert("Win!");
}
}
in the first if statement we're checking if the currently looped item in currently looped array (seems confusing, I know) is present in the test array. If not we already know that test array is not a winning array.
Moreover, I suggest wrapping all this stuff in a function like this:
function isWinner(playerNumbers, winningCombinations) {
var combLength = 0;
for (var i in winningCombinations) {
combLength = winningCombinations.length;
for (var j in winningCombinations[i]) {
if (-1 == playerNumbers.indexOf(winningCombinations[i][j]) {
break;
}
}
if (combLength - 1 == j) {
return true;
}
}
return false;
}
var test = [2,4,5,8]
var winningCombinations = [[1,2,3],[4,5,6],[7,8,9],[1,4,7],[2,5,8],[3,6,9],[1,5,9],[3,5,7]];
if (isWinner(test, winningCombinations)) {
alert("Win!");
} else {
alert ("No win.");
}
You really arent checking equality, you're checking if one array is a subset of another. For this, I would recommend changing test to an object in the form {2: 1, 4: 1, 5: 1, 8: 1}. The ones are in there just to evaluate to true, they don't really matter. The important thing is the key.
function checkSubset(a, b) {
//returns true if EVERY element in the array causes the next function to return true
return a.every(function(e) {
return !!b[e]; //returns true if b contains e
});
}
Then call checkSubset(winningCombinations[x], test).
That being said, there are much better ways to evaluate the state of a tic tac toe board.
The naive method would just check every combination and make sure test contains every element of one of the combinations:
var winner = false;
for (var i = 0; i < winningCombinations.length && !winner; i++) {
var matches = true;
for(var j = 0; j < winningCombinations[i].length && matches; j++)
if(test.indexOf(winningCombinations[i][j]) == -1)
matches = false;
if(matches)
winner = true;
}
If you encapsulate these in functions and return matches and winner you can get rid of the ugly loop conditions:
function matchesCombination(test, combination)
{
for(var i = 0; i < combination.length; i++)
if(text.indexOf(combination[i]) == -1)
return false;
return true;
}
function isWinner(test, combinations)
{
for(var i = 0; i < combinations.length; i++)
if(matchesCombination(test, combinations[i])
return true;
return false;
}
It may not be the best answer, but off the top of my head you could loop through the values in the winning conditions and do an if statement that requires all 3 indexOfs to be != -1.
i.e. for each array in winning combinations, loop through each value in the array and do test.indexOf(value) and check to see that it's not -1. If all 3 values come back as not equal to -1 then you have a win condition.

Categories