How can i handle multiple input values to one output value?
function c(input,val){
return input.indexOf(val)>-1;
}
function result(i){
if(c(i,1) && c(i,2) && c(i,3)){
return "alpha";
}else if(c(i,1) && c(i,2) && !c(i,3)){
return "beta";
}else if(c(i,1) && !c(i,2) && c(i,3)){
return "gamma";
}else if(c(i,1) && !c(i,2)){
return "delta";
}else if(c(i,3)){
return "theta";
}
//..... and so on covering all possible combinations
return null;
}
result([1,2,3]); //output : alpha
result([1,3,2]); //output : alpha
result([1,3,1,1]); //output : gamma
result([1,2,4]); //output : beta
result([3]); //output : theta
Number of values in array can be N, but from a predefined set of values only
What is the right way to work with so many combinations?
Based on Condor's answer, the following should do the job. It uses a sequence of tests to work out the result and also implements the "not" tests. If a value is "true" it must appear, if a value is "false" it must not appear. If it isn't mentioned, it doesn't matter if it's in the values or not.
Duplicates aren't an issue, values are processed until one fails. Removing duplicates first might speed it up a bit though.
The result is the name of the first set of tests that pass.
function testValues(values) {
var checks = [
{alpha: {1:true, 2:true, 3:true }},
{beta : {1:true, 2:true, 3:false}},
{gamma: {1:true, 2:false, 3:true }},
{theta: {3:true}}
];
var check, resultName, tests, passed;
// Do checks in sequence
for (var i=0, iLen=checks.length; i<iLen; i++) {
check = checks[i]
// Get name of result to return if the checks pass
for (resultName in check) {
// Make sure result is own property
if (check.hasOwnProperty(resultName)) {
// Passed is true until a fail is found
passed = true;
// Get tests to perform
tests = check[resultName];
// For each value in tests, make sure value exists or doesn't in values
for (var v in tests) {
if (tests.hasOwnProperty(v)) {
// Only test if passed is true
if (passed) {
// Note that indexOf uses === so must have same type
// Property names are always strings so if passing numbers,
// Must convert to numbers
passed = tests[v] === (values.indexOf(+v) != -1);
}
}
}
// If passed tests, return
if (passed) return resultName;
}
}
}
return 'failed all tests...';
}
console.log(testValues([1,2,3])); //output : alpha
console.log(testValues([1,3,2])); //output : alpha
console.log(testValues([1,3,1,1])); //output : gamma
console.log(testValues([1,2,4])); //output : beta
console.log(testValues([3])); //output : theta
The code could be a bit shorter if Object.keys is used with forEach, but the above is a bit clearer (perhaps), it can be refactored to be shorter. The above will work in ECMA-262 ed 3 environments if a shim for Array.prototype.indexOf is provided.
Edit
If modern features are used, the code can be simplified a bit. Providing support for older browsers isn't difficult:
// These are sufficient to support the function but are not suitable for general use
// Better versions are avaialble at MDN, see links below
if (!Object.keys) {
Object.keys = function(obj) {
var keys = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
keys.push(key);
}
}
return keys;
};
}
if (!Array.prototype.indeOf) {
Array.prototype.indexOf = function (value) {
for (var i=0, iLen=this.length; i<iLen; i++) {
if (this[i] === value) return i;
}
return -1;
};
}
function testValues(values) {
var checks = [
{alpha: {1:true, 2:true, 3:true }},
{beta : {1:true, 2:true, 3:false}},
{gamma: {1:true, 2:false, 3:true }},
{theta: {3:true}}
];
var check, passed, resultName, tests, testKeys;
for (var i=0, iLen=checks.length; i<iLen; i++) {
check = checks[i]
resultName = Object.keys(check)[0];
passed = true;
tests = check[resultName];
testKeys = Object.keys(tests);
for (var j=0, jLen=testKeys.length; j<jLen && passed; j++) {
passed = tests[testKeys[j]] === (values.indexOf(+testKeys[j]) != -1);
}
if (passed) return resultName;
}
return 'failed all tests...';
}
Object.keys: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
Array.prototype.indexOf: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
The code could perhaps be organized more clearly if the cases are easier accessible. For instance, the alpha case could be formualted by an array [1,2,3] which would list the numbers on which the code depend and and array of boolean values [true,true,true] which would indicate whether the corresponding number occurs or not. The checking could be implemented with a function as follows.
function check_case(values,bools){
var Result = true;
for ( var i = 0; i < values.length; i++ ){
Result = Result && ( c(values[i]) == bools[i] );
}
return Result;
}
This circumvents the formulation of conditions in which results of c have to be negated individually, which makes them difficult to follow and edit.
The idea could be taken a step further by having an array of cases which would also hold the names of the cases. An array containing the first two cases above would then be as follows.
[
{
values: [1,2,3],
bools: [true,true,true],
name: 'alpha'
},
{
values: [1,2,3],
bools: [true,true,false],
name: 'beta'
}
]
The code would then iterate over this array, calling check_case for every index and returning the value of name for the first hit.
Let your predefined array be:- [3,2,1] (i am keeping this short for simplicity, this can extend to N elements)
predefined array as boolean string can be visualized as:- 123
You can treat this number as boolean and create your desired output mapping:-
Example:- If no number :- 000 0
If only 1 is present:- 100 4
If only 1 and 2 are present :- 110 6
and so on all the required boolean combinations can be defined
So for N numbers you can create a list of all the possible combinations you want
Example:- var definedSet = {"0":"Alpha","1":"beta","2":"gama","3":"x","4":"y","5":"z","6":"a","7":"b"};
Now take input and remove duplicates and check the location (bit location of the number and create a boolean value and map this to defined set)
Code:-
function sortAndRemoveDuplicates(arr) {
arr.sort( function(a, b) { return a - b; } );
var copy = arr.slice(0);
arr.length = 0;
for (var i = 0, len = copy.length; i < len; ++i) {
if (i == 0 || copy[i] != copy[i - 1]) {
arr.push(copy[i]);
}
}
return arr;
}
var definedArr = [3,2,1];
var definedSet = {"0":"Alpha","1":"beta","2":"gama","3":"x","4":"y","5":"z","6":"a","7":"b"};
var inputArr=[1,4,3,1,1];
sortAndRemoveDuplicates(inputArr);
var outBooleanValue = 0;
for(var i=0;i<inputArr.length;i++)
{
var numIndex =definedArr.indexOf(inputArr[i]);
if(numIndex!=-1)
{
outBooleanValue+=Math.pow(2,numIndex);
}
}
result =definedSet[outBooleanValue.toString()];
alert(result);
Here is the working fiddle:-
http://jsfiddle.net/9tFnn/1/
Here is another version of this where predefined inputs are not required and it allows you to give conditions as you specified:-
var definedSet = {"1":"alpha","12":"beta","12!3":"gama","123":"delta"};
$("#defined-set").html(JSON.stringify(definedSet));
var inputArr=[1,2];
$("#input").html(JSON.stringify(inputArr));
$.unique(inputArr);
inputArr.sort();
var outputStr = inputArr.join('');
var regexStr = '';
var loopCounter=0;
for(loopCounter=0;loopCounter<outputStr.length;loopCounter++)
regexStr+='(!\\d)*'+outputStr[loopCounter]+'(!\\d)*';
regexStr+='$';
//var regexPattern = new RegExp(regexStr);
console.log(regexStr);
for(var currSet in definedSet)
{
//var match = regexPattern.test(currSet);
var match = currSet.search(regexStr);
if(match!=-1)
{
if(currSet==outputStr)
{
$("#result").append("Exact Match::");
}
$("#result").append(currSet+"<br/>");
}
}
Here is the link to working fiddle:-
http://jsfiddle.net/hLUuF/1/
Note:- This is just a basic prototype of the algorithm used to get to the answer, this can be modified according to the programming needs.
Hope this proves to be useful.
This solution assumes that the order of elements in the input is not important. That is, an input of [1, 3, 2] is the same as an input of [1, 2, 3].
It looks like what you're trying to do is take a set of possible inputs from a range (1..n), each of which may or may not be present. In other words, for a range of [1, 2, 3, 4], one possible input would be [1, 3]. Or,
Out of: [1, 2, 3, 4]
We want: [x, 0, x, 0]
Which looks suspiciously like a binary number, especially if we reverse the order. So all we really need to do is
Convert our input to a binary number
Use that binary number as an index into a predefined look-up table of values
For the first part all we need to do is loop through the input values and OR the appropriate bits together. This also automatically takes care of any duplicates.
for (i=0;i<input_array.length;i++)
{
num = num | (1 << (input_array[i] - 1));
}
The - 1 in there is because our sequence starts from 1 rather than 0. So an input of 4 will result in 1000 and an input of 2 will result in 0010. OR-ing them together gives us 1010 or 10 (decimal).
Now num contains the index into our table which we set up beforehand:
values[0] = "alpha"; // Corresponding to input []
values[1] = "beta"; // Corresponding to input [1]
...
values[10] = "gamma"; // Corresponding to input [4, 2] - remember, it's reversed
...
values[15] = "theta"; // Corresponding to input [4, 3, 2, 1]
Related
I need to write a program that, when given a list of integers, it finds all 2-pairs of integers that have the same product. i.e. a 2-pair is 2 distinct pairs of integers lets say [(a,b),(c,d)] where a*b = c*d but a ≠ b ≠ c ≠ d.
The range of integers should be from 1 to 1024. What I would like to implement is that when the web page is opened the user is prompted by a pop up in which he will enter the array of integers, i.e [1,2,3,7,8,9,6] etc for instance from the input [1,2,3,7,8,9,6] the output should be [(9,2),(3,6)] since both evaluate to 18.
The coding I did so far is very basic and can be seen below. What I've done so far is the pop-up box alert the input etc, but can't seem to understand how to make the program check for the pairs and give the sum. Thanks in advance to this community who's helping me out to better understand and learn javascript!
I've done my fair bit of research below, definitely different question than mine but have gone through them.
Find a pair of elements from an array whose sum equals a given number
https://www.w3resource.com/javascript-exercises/javascript-array-exercise-26.php
Code:
function evaluate() {
const input = prompt("Please enter the array of integers in the form: 1,2,3,1")
.split(',')
.map(item => item.trim());
function pairs(items) {
}
if (input == "" || input == null) {
document.writeln("Sorry, there is nothing that can be calculated.");
} else {
document.writeln("Your calculation is: ");
document.writeln(pairs(input) + " with a starting input string of: " + input);
}
}
evaluate()
You could iterate the array and a copy of the array beginning by the actual index plus one for getting the products. Store the result in an object with product as key.
Then get the keys (products) of the object, filter it to get only the results with two or more products.
var array = [1, 2, 3, 7, 8, 9, 6],
result = {},
pairs;
array.forEach(function (a, i) {
array.slice(i + 1).forEach(function (b) {
(result[a * b] = (result[a * b] || [])).push([a, b]);
});
});
pairs = Object
.keys(result)
.filter(function (k) { return result[k].length >= 2; })
.map(function(k) { return result[k]; });
console.log(pairs);
We could mutate the equation:
a * b = c * d | : b
a = c * d : b
So actually we just need to get all different combinations of three numbers (b, c, d) and check if the result (a) is also in the given range:
while(true){
// shuffle
const [b, c, d] = items;
const a = c * d / b;
if(items.includes(a + ""))
return true;
}
return false;
Now you only need to shuffle the array to go through all different combinations. You can find an algorithm here
Assuming that you are given an array such as [1,2,3,7,8,9,6] and a value 18 and you need to find pairs that multiply to 18 then, use the following approach
Convert them to a map - O(n)
var inputArr = [1,2,3,7,8,9,6];
var map = inputArr.reduce( (acc, c) => {
acc[ c ] = true; //set any truthy value
return acc;
},{});
Iterate an inputArr and see if its compliment is available in the map - O(n)
var output = [];
var mulValue = 18;
inputArr.forEach( s => {
var remainder = mulValue/s;
if ( map[s] && map[remainder] )
{
output.push( [ s, remainder ] );
map[s] = false;
map[remainder] = false;
}
});
Demo
var inputArr = [1, 2, 3, 7, 8, 9, 6];
var map = inputArr.reduce((acc, c) => {
acc[c] = true; //set any truthy value
return acc;
}, {});
var output = [];
var mulValue = 18;
inputArr.forEach(s => {
var remainder = mulValue / s;
if (map[s] && map[remainder]) {
output.push([s, remainder]);
map[s] = false;
map[remainder] = false;
}
});
console.log(output);
You can try something like this:
Idea:
Loop over the array to compute product. Use this iterator(say i) as get first operand(say op1).
Now again loop over same array but the range will start from i+1. This is to reduce number of iteration.
Now create a temp variable that will hold product and operand.
On every iteration, add value to product in hashMap.
Now loop over hashMap and remove any value that has length that is less than 2.
function sameProductValues(arr) {
var hashMap = {};
for (var i = 0; i < arr.length - 1; i++) {
for (var j = i + 1; j < arr.length; j++) {
var product = arr[i] * arr[j];
hashMap[product] = hashMap[product] || [];
hashMap[product].push([arr[i], arr[j]]);
}
}
for(var key in hashMap) {
if( hashMap[key].length < 2 ) {
delete hashMap[key];
}
}
console.log(hashMap)
}
sameProductValues([1, 2, 3, 7, 8, 9, 6])
I am having trouble checking the contents of an array contained within a main array.
Example:
I have two arrays
var main = [[1,2,3],
[4,5,6]];
var compare = [1,2,4,5,6]
I want to compare the array "compare" with each array within the array "main" to see if it contains any of the numbers. The result would be something I could then test against (boolean or the index position).
I tried indexOf and couldn't figure it out.
Edit
This should still return true:
var main = [[1,2,3], // returns false
[4,5,6], // returns false
[7,8,9], // returns true
[2,3,7]]; // returns true
var compare = [2,3,4,6,7,8,9]
** Update w/ Solution ***
I needed to check if compare array's contents matched any of the subarrays in main. Here's what I came up with:
var main = [[1, 2, 3],
[4,5,6]];
var counter = 0;
var counter2 = 0;
var compare = [4,1,3,2];
for (var i = 0; i <= compare.length; i++) {
// Sorting
compare.sort();
if (main[0].indexOf(compare[i]) > -1) {
counter++;
console.log("Added a point to counter 1");
} else if (main[1].indexOf(compare[i]) > -1) {
counter2++;
console.log("Added a point to counter 2");
} else {
console.log("No points added");
}
}
// if any of the counters have 3 marks, then the player hit it 3 times.
if (counter == 3 || counter2 === 3){
console.log("A counter is at 3");
}
Any feedback on what I came up with? What's a better way of doing this?
You'll need 2 loops, the first to iterate over your array of arrays, the next to check for existing elements within the current array:
for (var i = 0; i < main.length; i++) {
for (var j = 0; j < main[i].length; j++) {
if (compare.indexOf(main[i][j]) {
//compare has a number from the current array! main[i][j] exists in compare!
}
}
}
Take a look at lodash library, the have that exact functionality written already
You can use built-in array methods:
var result = main.map(function(xs) {
return xs.some(function(x) {
return compare.indexOf(x) > -1
})
})
It will return [true, true]
Following, two of the possible solutions:
Suppose:
var main = [[1,2,3],
[4,5,6],
[7,8,9],
[2,3,7],
[5,1,10]];
var compare = [2,3,4,6,7,8,9];
First solution: return true if any element of the main inner array is included in the master one which is compare:
var result1= main.map(function(element,index,array){
return element.reduce(function(previousValue, currentValue, index, array){
return (previousValue || (compare.indexOf(currentValue) >= 0));
}, false);
});
This solution gives the following result:
result1 = [true,true,true,true,false]
Second solution: return the index of the main inner array elements in compare:
var result2= main.map(function(element,index,array){
return element.map(function(element,index,array){
return (compare.indexOf(element));
});
});
This solution gives the following result:
result2 = [[-1,0,1],[2,-1,3],[4,5,6],[0,1,4],[-1,-1,-1]]
Check this link jsfiddle to see a working example.
Hope it's useful!
I've been trying to find a reasonably concise way to set the dimensions of an empty multidimensional JavaScript array, but with no success so far.
First, I tried to initialize an empty 10x10x10 array using var theArray = new Array(10, 10 10), but instead, it only created a 1-dimensional array with 3 elements.
I've figured out how to initialize an empty 10x10x10 array using nested for-loops, but it's extremely tedious to write the array initializer this way. Initializing multidimensional arrays using nested for-loops can be quite tedious: is there a more concise way to set the dimensions of empty multidimensional arrays in JavaScript (with arbitrarily many dimensions)?
//Initializing an empty 10x10x10 array:
var theArray = new Array();
for(var a = 0; a < 10; a++){
theArray[a] = new Array();
for(var b = 0; b < 10; b++){
theArray[a][b] = new Array();
for(var c = 0; c < 10; c++){
theArray[a][b][c] = 10
}
}
}
console.log(JSON.stringify(theArray));
Adapted from this answer:
function createArray(length) {
var arr = new Array(length || 0),
i = length;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while(i--) arr[i] = createArray.apply(this, args);
}
return arr;
}
Simply call with an argument for the length of each dimension.
Usage examples:
var multiArray = createArray(10,10,10); Gives a 3-dimensional array of equal length.
var weirdArray = createArray(34,6,42,2); Gives a 4-dimensional array of unequal lengths.
function multiDimArrayInit(dimensions, leafValue) {
if (!dimensions.length) {
return leafValue;
}
var arr = [];
var subDimensions = dimensions.slice(1);
for (var i = 0; i < dimensions[0]; i++) {
arr.push(multiDimArrayInit(subDimensions, leafValue));
}
return arr;
}
console.log(multiDimArrayInit([2,8], "hi")); // counting the nested "hi"'s yields 16 of them
demo http://jsfiddle.net/WPrs3/
Here is my take on the problem: nArray utility function
function nArray() {
var arr = new Array();
var args = Array.prototype.slice.call(arguments, 1);
for(var i=0;i<arguments[0];i++) {
arr[i] = (arguments.length > 1 && nArray.apply(this, args)) || undefined;
}
return arr;
}
Usage example:
var arr = nArray(3, 3, 3);
Results in 3x3x3 array of undefined values.
Running code with some tests also available as a Fiddle here: http://jsfiddle.net/EqT3r/7/
The more dimension you have, the more you have interest in using one single flat array and a getter /setter function for your array.
Because for a [d1 X d2 X d3 X .. X dn] you'll be creating d2*d3*...*dn arrays instead of one, and when accessing, you'll make n indirection instead of 1.
The interface would look like :
var myNArray = new NArray(10,20,10);
var oneValue = myNArray.get(5,8,3);
myNArray.set(8,3,2, 'the value of (8,3,2)');
the implementation depends on your preference for a fixed-size
n-dimensionnal array or an array able to push/pop and the like.
A more succinct version of #chris code:
function multiDim (dims, leaf) {
dims = Array.isArray (dims) ? dims.slice () : [dims];
return Array.apply (null, Array (dims.shift ())).map (function (v, i) {
return dims.length
? multiDim (dims, typeof leaf == 'string' ? leaf.replace ('%i', i + ' %i') : leaf)
: typeof leaf == 'string' ? leaf.replace ('%i', i) : leaf;
});
}
console.log (JSON.stringify (multiDim ([2,2], "hi %i"), null, ' '));
Produces :
[
[
"hi 0 0",
"hi 0 1"
],
[
"hi 1 0",
"hi 1 1"
]
]
In this version you can pass the first argument as a number for single dimension array.
Including %i in the leaf value will provide index values in the leaf values.
Play with it at : http://jsfiddle.net/jstoolsmith/r3eMR/
Very simple function, generate an array with any number of dimensions. Specify length of each dimension and the content which for me is '' usually
function arrayGen(content,dims,dim1Len,dim2Len,dim3Len...) {
var args = arguments;
function loop(dim) {
var array = [];
for (var a = 0; a < args[dim + 1]; a++) {
if (dims > dim) {
array[a] = loop(dim + 1);
} else if (dims == dim) {
array[a] = content;
}
}
return array;
}
var thisArray = loop(1);
return thisArray;
};
I use this function very often, it saves a lot of time
I'd like to check for a variable within my array. It works if the number matches my value directly. How can I get it to match the previous value if it's below the match. From my code :
var assassin_bp = {
fhr: { 7:8, 15:7, 27:6, 48:5, 86:4, 200:3 },
fcr: { 8:15, 16:14, 27:13, 42:12, 65:11, 102:10, 174:9 }
}
var char_fhr = 48;
var fhr_frames = assassin_bp[ 'fhr' ][ [char_fhr] ]
with char_fhr worth 48, fhr_frames returns 5,
if char_fhr was worth 47 (or any number from 27 to 47), fhr_frames should return 6,
if char_fhr was worth 49 (or any number from 48 to 85), fhr_frames should return 5
I'm clueless on where to start. Can an object include a range? Should I have a function checking for it?
You need to iterate over the object properties and compare their names against your target value. See for...in [MDN] and Working with Objects [MDN].
function valueForClosestKey(obj, target) {
// get all keys smaller than or equal to `target`
var keys = [];
for(var k in obj) {
if(k <= target) {
keys.push(k);
}
}
// order keys in ascending order
keys.sort(function(a, b) {
return a - b;
});
// e.g. `keys` is now [7, 15, 27, 48]
// get the "closest" key, which is the last one in the array
if(keys.length > 0) {
return obj[keys.pop()];
}
// if there are no keys smaller than `target` (i.e. `keys` is empty),
// we just don't return anything (implicitly returns `undefined`)
}
var value = valueForClosestKey(assassin_bp[ 'fhr' ], char_fhr);
It is necessary to extract and sort the keys this way because the order in which an object is iterated is implementation dependent. I.e. it is not guaranteed that the properties are in the correct numerical order.
http://jsfiddle.net/aquinas/QP6aF/
How about:
var assassin_bp = {
fhr: { 7:8, 15:7, 27:6, 48:5, 86:4, 200:3 },
fcr: { 8:15, 16:14, 27:13, 42:12, 65:11, 102:10, 174:9 }
}
var arr = [];
for (var prop in assassin_bp.fhr){
if (assassin_bp.fhr.hasOwnProperty(prop)){
arr.push(parseInt(prop));
}
}
arr.sort(function(a,b){return a-b;});
function calcScore(val){
if (arr[0] > val){
return assassin_bp.fhr[arr[0]];
}
for (var i=arr.length; i>=0; i--){
if (val >= arr[i]){
return assassin_bp.fhr[arr[i]];
}
}
}
//test to see if this works:
for (var i=0; i<300; i++){
document.write(i + " - " + calcScore(i) + "<br/>");
}
For some reason I'm having some serious difficulty wrapping my mind around this problem. I need this JS function that accepts 2 arrays, compares the 2, and then returns a string of the missing element. E.g. Find the element that is missing in the currentArray that was there in the previous array.
function findDeselectedItem(CurrentArray, PreviousArray){
var CurrentArrSize = CurrentArray.length;
var PrevousArrSize = PreviousArray.length;
// Then my brain gives up on me...
// I assume you have to use for-loops, but how do you compare them??
return missingElement;
}
Thank in advance! I'm not asking for code, but even just a push in the right direction or a hint might help...
Problem statement:
Find the element that is missing in the currentArray that was there in the previous array.
previousArray.filter(function(x) { // return elements in previousArray matching...
return !currentArray.includes(x); // "this element doesn't exist in currentArray"
})
(This is as bad as writing two nested for-loops, i.e. O(N2) time*). This can be made more efficient if necessary, by creating a temporary object out of currentArray, and using it as a hashtable for O(1) queries. For example:)
var inCurrent={}; currentArray.forEach(function(x){ inCurrent[x]=true });
So then we have a temporary lookup table, e.g.
previousArray = [1,2,3]
currentArray = [2,3];
inCurrent == {2:true, 3:true};
Then the function doesn't need to repeatedly search the currentArray every time which would be an O(N) substep; it can instantly check whether it's in currentArray in O(1) time. Since .filter is called N times, this results in an O(N) rather than O(N2) total time:
previousArray.filter(function(x) {
return !inCurrent[x]
})
Alternatively, here it is for-loop style:
var inCurrent = {};
var removedElements = []
for(let x of currentArray)
inCurrent[x] = true;
for(let x of previousArray)
if(!inCurrent[x])
removedElements.push(x)
//break; // alternatively just break if exactly one missing element
console.log(`the missing elements are ${removedElements}`)
Or just use modern data structures, which make the code much more obvious:
var currentSet = new Set(currentArray);
return previousArray.filter(x => !currentSet.has(x))
*(sidenote: or technically, as I illustrate here in the more general case where >1 element is deselected, O(M*N) time)
This should work. You should also consider the case where the elements of the arrays are actually arrays too. The indexOf might not work as expected then.
function findDeselectedItem(CurrentArray, PreviousArray) {
var CurrentArrSize = CurrentArray.length;
var PreviousArrSize = PreviousArray.length;
// loop through previous array
for(var j = 0; j < PreviousArrSize; j++) {
// look for same thing in new array
if (CurrentArray.indexOf(PreviousArray[j]) == -1)
return PreviousArray[j];
}
return null;
}
Take a look at underscore difference function: http://documentcloud.github.com/underscore/#difference
I know this is code but try to see the difference examples to understand the way:
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
isMatch = false,
missing = null;
var i = 0, y = 0,
lenC = current.length,
lenP = prev.length;
for ( ; i < lenC; i++ ) {
isMatch = false;
for ( y = 0; y < lenP; y++ ) {
if (current[i] == prev[y]) isMatch = true;
}
if ( !isMatch ) missing = current[i]; // Current[i] isn't in prev
}
alert(missing);
Or using ECMAScript 5 indexOf:
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
missing = null;
var i = 0,
lenC = current.length;
for ( ; i < lenC; i++ ) {
if ( prev.indexOf(current[i]) == -1 ) missing = current[i]; // Current[i] isn't in prev
}
alert(missing);
And with while
var current = [1, 2, 3, 4],
prev = [1, 2, 4],
missing = null,
i = current.length;
while(i) {
missing = ( ~prev.indexOf(current[--i]) ) ? missing : current[i];
}
alert(missing);
This is my approach(works for duplicate entries too):-
//here 2nd argument is actually the current array
function(previousArray, currentArray) {
var hashtable=[];
//store occurances of elements in 2nd array in hashtable
for(var i in currentArray){
if(hashtable[currentArray[i]]){
hashtable[currentArray[i]]+=1; //add 1 for duplicate letters
}else{
hashtable[currentArray[i]]=1; //if not present in hashtable assign 1
}
}
for(var i in previousArray){
if(hashtable[previousArray[i]]===0 || hashtable[previousArray[i]] === undefined){ //if entry is 0 or undefined(means element not present)
return previousArray[i]; //returning the missing element
}
else{
hashtable[previousArray[i]]-=1; //reduce count by 1
}
}
}
Logic is that i have created a blank array called hashtable. We iterate currentArray first and use the elements as index and values as counts starting from 1(this helps in situations when there are duplicate entries). Then we iterate through previousArray and look for indexes, if they match we reduce the value count by 1. If an element of 2nd array doesnt exist at all then our undefined check condition fires and we return it. If duplicates exists, they are decremented by 1 each time and when 0 is encountered, that elment is returned as missing element.