I'm trying to return the mode of an array. I have an inner loop and outer comparing each element to each other. Array = [5,3,6,3,3,3].
function mode(arr){
for (var i = 0; i < arr.length; i++) {
for (var k = i+1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
}else {
otherItems +=arr[i];
}
}
}return modeItems;
}
Result comes back "333333" instead of "3333". I see how this is happening on an excel sheet comparing the 15 total loops aar[i] and arr[k], but I'm not sure what to do.
Below is a hodgepodge answer. My confusion stems from the title
How to eliminate extra matches of element in single array
mixed with this part of the question
I'm trying to return the mode of an array.
Reducing an array to an array of single instances, and an array of all duplicates.
DEMO
var arra = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function simplify(arr) {
var c = {}, o = [], d = [], i;
for (i = 0; i < arr.length; i++) {
if (!c.hasOwnProperty(arr[i])) {
c[arr[i]] = arr[i];
o.push(arr[i]);
} else {
d.push(arr[i]);
}
}
return {
reduced: o,
duplicates: d
};
}
console.log(simplify(arra));
// >> [object Object] {
// >> duplicates: [2, 3, 3, 4, 4, 4],
// >> reduced: [1, 2, 3, 4]
// >> }
Removing duplicates from an array in place.
DEMO
var arr = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4];
function elim (arra) {
var c = {}, i = 0;
while (i < arra.length) {
if (c[arra[i]]) {
arra.splice(i, 1);
} else {
c[arra[i]] = true;
i++;
}
}
return arra; // only required for debug.
}
console.log(elim(arr.slice()));
Looping that many times on an array just to find the mode is unnecessary. You can use an object literal as a cache to update your counts. If you want an array minus the mode (or an array with only the mode), you can use .filter afterwards.
Here's a basic implementation. We return null if there is no mode.
DEMO
function findMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
var arr = [5,3,6,3,3,3],
myMode = findMode(arr),
filteredArr = arr.filter(function (e) {
return (e !== myMode);
}),
modeItems = arr.filter(function (e) {
return (e === myMode);
});
console.log(arr); // >> [5,3,6,3,3,3]
console.log(myMode); // >> 3
console.log(filteredArr); // >> [5, 6]
console.log(modeItems); // >> [3, 3, 3, 3]
No mode here:
findMode([5, 7, 5, 7]); // >> null
Something slightly more complex. Returns the mode, mode array, and inverse array in two passes of the original array.
DEMO
var findMode = (function () {
function getMode (a) {
var cache = {},
len = a.length,
mode,
max = 0,
matched = false;
for (var i = 0; i < len; i++) {
cache[a[i]] = (cache[a[i]] + 1 || 1);
if (cache[a[i]] === max) {
matched = true;
} else if (cache[a[i]] > max) {
max = cache[a[i]];
mode = a[i];
matched = false;
}
}
return (matched ? null : mode);
}
function split (arr, mode) {
var set = [],
inverse = [];
if (mode !== null) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === mode) {
set.push(arr[i]);
} else {
inverse.push(arr[i]);
}
}
}
return [set, inverse];
}
return (function (arr) {
var mode = getMode(arr),
lists = split(arr, mode);
return {
mode: mode,
set: lists[0],
inverse: lists[1]
};
});
}());
var info = findMode([5,3,6,3,3,3]),
noMode = findMode([5, 7, 5, 7]);
console.log(info);
console.log(noMode);
Maintain an object array for keeping processed items and ignore the item in the next iterator that are already processed.
function mode(arr) {
var processed = {};
for (var i = 0; i < arr.length; i++) {
for (var k = i + 1; k < arr.length; k++) {
if (arr[i] == arr[k]) {
modeItems += arr[k];
modeItems += !processed[arr[k]] ? arr[k] : '';
processed[arr[k]] = i;
break;
} else {
otherItems += arr[i];
}
}
}
return modeItems;
}
Output: 3,3,3,3
your code is working matching , for every number in the loop , the numbers after the index i+1 :
[5,3,6,3,3,3]
^ ^ //first match
[5,3,6,3,3,3]
^ ^ // match 2
[5,3,6,3,3,3]
^ ^ // match 3
[5,3,6,3,3,3]
^ ^ // match 4
[5,3,6,3,3,3]
^ ^ // match 5
[5,3,6,3,3,3]
^ ^ // match 6
a simple way to work around this issue would be to reset loop with continue if i has already been matched; but it would fail if you had multiple double occurrences..
Let me also add my two cents. This code delete matched items to don't use it again :)
function mode(arr){
var key = arr[0], // it wil be the mode, current value of array
count = 1, // it will be the count of mode value
icount;
for (var i = 0; i < arr.length-count+1; i++) { // there is no need to look any further -
// count is more then rest items
if (!arr[i]) continue;
icount = 1;
for (var k = i+1; k < arr.length; k++) {
if (!arr[k]) continue;
if (arr[i] == arr[k]) { icount++; delete arr[k]; }
}
if (icount > count) { count = icount; key = arr[i]; }
}
if (count == 1) ret = null; // At this moment key - mode. Below output
else { var ret = []; while(count--) ret[count] = key; ret = ret.join();}
return ret;
}
Related
How to write in javascript(w/wth JQuery) to find values that intersect between arrays?
It should be like
var a = [1,2,3]
var b = [2,4,5]
var c = [2,3,6]
and the intersect function should returns array with value {2}. If possible it could applicable for any number of arrays.
Thanks
There are many ways to achieve this.
Since you are using jQuery I will suggest use grep function to filter the value that are present in all three array.
var a = [1, 2, 3]
var b = [2, 4, 5]
var c = [2, 3, 6]
var result = $.grep(a, function(value, index) {
return b.indexOf(value) > -1 && c.indexOf(value) > -1;
})
console.log(result)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Explanation: Loop over any array and filter out the values that are present in other array.
Update (for multimidensional array):
Concept - flatten the multidimensional array that is transform [[1,2],3,4] to [1,2,3,4] and then use the same logic used for single dimensional array.
Example:
var a = [
[1, 4], 2, 3
]
var b = [2, 4, 5]
var c = [2, 3, 6, [4, 7]]
//flatten the array's
//[1,4,2,3]
var aFlattened = $.map(a, function(n) {
return n;
})
//[2,4,5]
var bFlattened = $.map(b, function(n) {
return n;
})
//[2,3,6,4,7]
var cFlattened = $.map(c, function(n) {
return n;
})
var result = $.grep(aFlattened, function(value) {
return (bFlattened.indexOf(value) > -1 && cFlattened.indexOf(value) > -1);
});
console.log(result);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
// First this is how you declare an array
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// Second, this function should handle undetermined number of parameters (so arguments should be used)
function intersect(){
var args = arguments;
// if no array is passed then return empty array
if(args.length == 0) return [];
// for optimisation lets find the smallest array
var imin = 0;
for(var i = 1; i < args.length; i++)
if(args[i].length < args[imin].length) imin = i;
var smallest = Array.prototype.splice.call(args, imin, 1)[0];
return smallest.reduce(function(a, e){
for(var i = 0; i < args.length; i++)
if(args[i].indexOf(e) == -1) return a;
a.push(e);
return a;
}, []);
}
console.log(intersect(a, b, c));
First of all '{}' means Object in JavaScript.
Here is my suggestion.(this is another way of doing it)
// declarations
var a = [1,2,3];
var b = [2,4,5];
var c = [2,3,6];
// filter property of array
a.filter(function(val) {
if (b.indexOf(val) > -1 && c.indexOf(val) > -1)
return val;
});
what it does is it checks for each element in array 'a' and checks if that value is present in array 'b' and array 'c'. If it is true it returns the value. Simple!!!. The above code should work for String as well but it wouldn't work for IE < 9, so be careful.
// Intersecting 2 ordered lists of length n and m is O(n+m)
// This can be sped up by skipping elements
// The stepsize is determined by the ratio of lengths of the lists
// The skipped elements need to be checked after skipping some elements:
// In the case of step size 2 : Check the previous element
// In case step size>2 : Binary search the previously skipped range
// This results in the best case complexity of O(n+n), if n<m
// or the more propable complexity of O(n+n+n*log2(m/n)), if n<m
function binarySearch(array, value, start = 0, end = array.length) {
var j = start,
length = end;
while (j < length) {
var i = (length + j - 1) >> 1; // move the pointer to
if (value > array[i])
j = i + 1;
else if (value < array[i])
length = i;
else
return i;
}
return -1;
}
function intersect2OrderedSets(a, b) {
var j = 0;
var k = 0;
var ratio = ~~(b.length / a.length) - 1 || 1;
var result = [];
var index;
switch (ratio) {
case 1:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k++;
if (k >= b.length) break;
}
}
break;
case 2:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += 2;
if (k - 1 >= b.length) break;
if (a[j] <= b[k - 1]) k--;
}
}
break;
default:
while (j < a.length) {
if (a[j] === b[k]) {
result.push(a[j]);
j++;
k++;
} else if (a[j] < b[k]) {
while (a[j] < b[k]) j++;
} else {
while (b[k] < a[j]) k += ratio;
index = binarySearch(b, a[j], k - ratio + 1, k + 1 < b.length ? k + 1 : b.length - 1);
if (index > -1) {
result.push(a[j]);
j++;
k = index + 1;
} else {
j++;
k = k - ratio + 1;
}
if (k >= b.length) break;
}
}
}
return result;
}
function intersectOrderedSets() {
var shortest = 0;
for (var i = 1; i < arguments.length; i++)
if (arguments[i].length < arguments[shortest].length) shortest = i;
var result = arguments[shortest];
for (var i = 0, a, b, j, k, ratio, index; i < arguments.length; i++) {
if (result.length === 0) return result;
if (i === shortest) continue;
a = result;
b = arguments[i];
result = intersect2OrderedSets(a, b);
}
return result;
}
How to use:
intersectOrderedSets(a,b,c);
I am in mid of my JavaScript session. Find this code in my coding exercise. I understand the logic but I didn't get this map[nums[x]] condition.
function twoSum(nums, target_num) {
var map = [];
var indexnum = [];
for (var x = 0; x < nums.length; x++)
{
if (map[nums[x]] != null)
// what they meant by map[nums[x]]
{
index = map[nums[x]];
indexnum[0] = index+1;
indexnum[1] = x+1;
break;
}
else
{
map[target_num - nums[x]] = x;
}
}
return indexnum;
}
console.log(twoSum([10,20,10,40,50,60,70],50));
I am trying to get the Pair of elements from a specified array whose sum equals a specific target number. I have written below code.
function arraypair(array,sum){
for (i = 0;i < array.length;i++) {
var first = array[i];
for (j = i + 1;j < array.length;j++) {
var second = array[j];
if ((first + second) == sum) {
alert('First: ' + first + ' Second ' + second + ' SUM ' + sum);
console.log('First: ' + first + ' Second ' + second);
}
}
}
}
var a = [2, 4, 3, 5, 6, -2, 4, 7, 8, 9];
arraypair(a,7);
Is there any optimized way than above two solutions? Can some one explain the first solution what exactly map[nums[x]] this condition points to?
Using HashMap approach using time complexity approx O(n),below is the following code:
let twoSum = (array, sum) => {
let hashMap = {},
results = []
for (let i = 0; i < array.length; i++){
if (hashMap[array[i]]){
results.push([hashMap[array[i]], array[i]])
}else{
hashMap[sum - array[i]] = array[i];
}
}
return results;
}
console.log(twoSum([10,20,10,40,50,60,70,30],50));
result:
{[10, 40],[20, 30]}
I think the code is self explanatory ,even if you want help to understand it,let me know.I will be happy enough to for its explanation.
Hope it helps..
that map value you're seeing is a lookup table and that twoSum method has implemented what's called Dynamic Programming
In Dynamic Programming, you store values of your computations which you can re-use later on to find the solution.
Lets investigate how it works to better understand it:
twoSum([10,20,40,50,60,70], 50)
//I removed one of the duplicate 10s to make the example simpler
In iteration 0:
value is 10. Our target number is 50. When I see the number 10 in index 0, I make a note that if I ever find a 40 (50 - 10 = 40) in this list, then I can find its pair in index 0.
So in our map, 40 points to 0.
In iteration 2:
value is 40. I look at map my map to see I previously found a pair for 40.
map[nums[x]] (which is the same as map[40]) will return 0.
That means I have a pair for 40 at index 0.
0 and 2 make a pair.
Does that make any sense now?
Unlike in your solution where you have 2 nested loops, you can store previously computed values. This will save you processing time, but waste more space in the memory (because the lookup table will be needing the memory)
Also since you're writing this in javascript, your map can be an object instead of an array. It'll also make debugging a lot easier ;)
function twoSum(arr, S) {
const sum = [];
for(let i = 0; i< arr.length; i++) {
for(let j = i+1; j < arr.length; j++) {
if(S == arr[i] + arr[j]) sum.push([arr[i],arr[j]])
}
}
return sum
}
Brute Force not best way to solve but it works.
Please try the below code. It will give you all the unique pairs whose sum will be equal to the targetSum. It performs the binary search so will be better in performance. The time complexity of this solution is O(NLogN)
((arr,targetSum) => {
if ((arr && arr.length === 0) || targetSum === undefined) {
return false;
} else {
for (let x = 0; x <=arr.length -1; x++) {
let partnerInPair = targetSum - arr[x];
let start = x+1;
let end = (arr.length) - 2;
while(start <= end) {
let mid = parseInt(((start + end)/2));
if (arr[mid] === partnerInPair) {
console.log(`Pairs are ${arr[x]} and ${arr[mid]} `);
break;
} else if(partnerInPair < arr[mid]) {
end = mid - 1;
} else if(partnerInPair > arr[mid]) {
start = mid + 1;
}
}
};
};
})([0,1,2,3,4,5,6,7,8,9], 10)
function twoSum(arr, target) {
let res = [];
let indexes = [];
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (target === arr[i] + arr[j] && !indexes.includes(i) && !indexes.includes(j)) {
res.push([arr[i], arr[j]]);
indexes.push(i);
indexes.push(j);
}
}
}
return res;
}
console.log('Result - ',
twoSum([1,2,3,4,5,6,6,6,6,6,6,6,6,6,7,8,9,10], 12)
);
Brute force.
const findTwoNum = ((arr, value) => {
let result = [];
for(let i= 0; i< arr.length-1; i++) {
if(arr[i] > value) {
continue;
}
if(arr.includes(value-arr[i])) {
result.push(arr[i]);
result.push(value-arr[i]);
break;;
}
}
return result;
});
let arr = [20,10,40,50,60,70,30];
const value = 120;
console.log(findTwoNum(arr, value));
OUTPUT : Array [50, 70]
function twoSum(arr){
let constant = 17;
for(let i=0;i<arr.length-2;i++){
for(let j=i+1;j<arr.length;j++){
if(arr[i]+arr[j] === constant){
console.log(arr[i],arr[j]);
}
}
}
}
let myArr = [2, 4, 3, 5, 7, 8, 9];
function getPair(arr, targetNum) {
for (let i = 0; i < arr.length; i++) {
let cNum = arr[i]; //my current number
for (let j = i; j < arr.length; j++) {
if (cNum !== arr[j] && cNum + arr[j] === targetNum) {
let pair = {};
pair.key1 = cNum;
pair.key2 = arr[j];
console.log(pair);
}
}
}
}
getPair(myArr, 7)
let sumArray = (arr,target) => {
let ar = []
arr.forEach((element,index) => {
console.log(index);
arr.forEach((element2, index2) => {
if( (index2 > index) && (element + element2 == target)){
ar.push({element, element2})
}
});
});
return ar
}
console.log(sumArray([8, 7, 2, 5, 3, 1],10))
Use {} hash object for storing and fast lookups.
Use simple for loop so you can return as soon as you find the right combo; array methods like .forEach() have to finish iterating no matter what.
And make sure you handle edges cases like this: twoSum([1,2,3,4], 8)---that should return undefined, but if you don't check for !== i (see below), you would erroneously return [4,4]. Think about why that is...
function twoSum(nums, target) {
const lookup = {};
for (let i = 0; i < nums.length; i++) {
const n = nums[i];
if (lookup[n] === undefined) {//lookup n; seen it before?
lookup[n] = i; //no, so add to dictionary with index as value
}
//seen target - n before? if so, is it different than n?
if (lookup[target - n] !== undefined && lookup[target - n] !== i) {
return [target - n, n];//yep, so we return our answer!
}
}
return undefined;//didn't find anything, so return undefined
}
We can fix this with simple JS object as well.
const twoSum = (arr, num) => {
let obj = {};
let res = [];
arr.map(item => {
let com = num - item;
if (obj[com]) {
res.push([obj[com], item]);
} else {
obj[item] = item;
}
});
return res;
};
console.log(twoSum([2, 3, 2, 5, 4, 9, 6, 8, 8, 7], 10));
// Output: [ [ 4, 6 ], [ 2, 8 ], [ 2, 8 ], [ 3, 7 ] ]
Solution In Java
Solution 1
public static int[] twoNumberSum(int[] array, int targetSum) {
for(int i=0;i<array.length;i++){
int first=array[i];
for(int j=i+1;j<array.length;j++){
int second=array[j];
if(first+second==targetSum){
return new int[]{first,second};
}
}
}
return new int[0];
}
Solution 2
public static int[] twoNumberSum(int[] array, int targetSum) {
Set<Integer> nums=new HashSet<Integer>();
for(int num:array){
int pmatch=targetSum-num;
if(nums.contains(pmatch)){
return new int[]{pmatch,num};
}else{
nums.add(num);
}
}
return new int[0];
}
Solution 3
public static int[] twoNumberSum(int[] array, int targetSum) {
Arrays.sort(array);
int left=0;
int right=array.length-1;
while(left<right){
int currentSum=array[left]+array[right];
if(currentSum==targetSum){
return new int[]{array[left],array[right]};
}else if(currentSum<targetSum){
left++;
}else if(currentSum>targetSum){
right--;
}
}
return new int[0];
}
function findPairOfNumbers(arr, targetSum) {
var low = 0, high = arr.length - 1, sum, result = [];
while(low < high) {
sum = arr[low] + arr[high];
if(sum < targetSum)
low++;
else if(sum > targetSum)
high--;
else if(sum === targetSum) {
result.push({val1: arr[low], val2: arr[high]});
high--;
}
}
return (result || false);
}
var pairs = findPairOfNumbers([1,2,3,4,4,5], 8);
if(pairs.length) {
console.log(pairs);
} else {
console.log("No pair of numbers found that sums to " + 8);
}
Simple Solution would be in javascript is:
var arr = [7,5,10,-5,9,14,45,77,5,3];
var arrLen = arr.length;
var sum = 15;
function findSumOfArrayInGiven (arr, arrLen, sum){
var left = 0;
var right = arrLen - 1;
// Sort Array in Ascending Order
arr = arr.sort(function(a, b) {
return a - b;
})
// Iterate Over
while(left < right){
if(arr[left] + arr[right] === sum){
return {
res : true,
matchNum: arr[left] + ' + ' + arr[right]
};
}else if(arr[left] + arr[right] < sum){
left++;
}else{
right--;
}
}
return 0;
}
var resp = findSumOfArrayInGiven (arr, arrLen, sum);
// Display Desired output
if(resp.res === true){
console.log('Matching Numbers are: ' + resp.matchNum +' = '+ sum);
}else{
console.log('There are no matching numbers of given sum');
}
Runtime test JSBin: https://jsbin.com/vuhitudebi/edit?js,console
Runtime test JSFiddle: https://jsfiddle.net/arbaazshaikh919/de0amjxt/4/
function sumOfTwo(array, sumNumber) {
for (i of array) {
for (j of array) {
if (i + j === sumNumber) {
console.log([i, j])
}
}
}
}
sumOfTwo([1, 2, 3], 4)
function twoSum(args , total) {
let obj = [];
let a = args.length;
for(let i = 0 ; i < a ; i++){
for(let j = 0; j < a ; j++){
if(args[i] + args[j] == total) {
obj.push([args[i] , args[j]])
}
}
}
console.log(obj)}
twoSum([10,20,10,40,50,60,70,30],60);
/* */
Write an algorithm that takes an array and moves all of the zeros to the end, preserving the order of the other elements.
For example:
moveZeros([false,1,0,1,2,0,1,3,"a"]) // returns[false,1,1,2,1,3,"a",0,0]
My code:
var moveZeros = function (arr) {
var zeros = [];
var others = [];
var res;
var arrayLength = arr.length;
for (var i = 0; i < arrayLength; i++) {
if (arr[i] == 0) {
zeros.push(arr[i]);
} else {
others.push(arr[i]);
}
}
var res = others.concat( zeros );
return res;
}
I get the following result:
Expected: ["a","b",null,"c","d",1,false,1,3,[],1,9,{},9,0,0,0,0,0,0,0,0,0,0],
Instead got: ["a","b",null,"c","d",1,1,3,1,9,{},9,0,0,0,false,0,0,[],0,0,0,0,0]
The expected result is quite close to what I achieved (see above) . I don't understand why I have false in a different place?
try this simply
var arr = [false,1,0,1,2,0,1,3,"a"];
arr.sort(function(a,b){if (a===0){return 1}});
document.body.innerHTML += JSON.stringify(arr);
Try to use a normal for loop and splice at this context to make your job done,
var arr = [false,1,0,1,2,0,1,3,"a"];
for(var i=arr.length;i>0;i--){
if(arr[i] === 0){ arr.push(arr.splice(i,1).pop()); }
}
console.log(arr); //[false, 1, 1, 2, 1, 3, "a", 0, 0]
document.body.innerHTML += JSON.stringify(arr);
Use Array#splice() and Array#push().
function moveZeros(a) {
var i = a.length - 1;
while (i--) {
if (a[i] === 0) {
a.push(a.splice(i, 1)[0]);
}
}
return a;
};
var array = [false, 1, 0, 1, 2, 0, 1, 3, "a"];
document.write('<pre>' + JSON.stringify(moveZeros(array), 0, 4) + '</pre>');
Another approach with swapping items.
function moveZeros(array) {
var length = array.length,
i = length;
while (--i) {
if (array[i] !== 0) continue;
length--;
while (i < length) {
[array[i + 1], array[i]] = [array[i], array[i + 1]];
i++;
}
}
return array;
}
var array = [false, 1, 0, 1, 2, 0, 1, 3, "a"];
console.log(...moveZeros(array));
Please use === operator to compare if value is 0:
if (arr[i] === 0) {
zeros.push(arr[i]);
} else {
others.push(arr[i]);
}
The code snippet below should work , please try , reason for null is that the length of the arr starts count from zero so when using <= you should subtract 1 from the total length.
var moveZeros = function (arr) {
// TODO: Program me
let zero = []
let others = []
let together = []
for (let i =0; i <= arr.length-1; i++){
if (arr[i] === 0){
zero.push(arr[i])
}
else{
others.push(arr[i])
}
}
together = others.concat(zero)
return together
}
var titleCase = function(title) {
var arr = [];
for (i = 0; i < title.length ; i++) {
if (title[i] !== 0 ) {
arr.push(title[i]);
}
}
for (i = 0 ; i < title.length ; i++) {
if (title[i] == 0 ) {
arr.push(title[i]);
}
}
return arr;
}
You could use the filter() method to achieve your goal. With the arrow notation you can shorten the code. For example: arr => arr === 0 is the shorthand for the anonymous filter function function(arr) { return arr === 0; }
var moveZeros = function (arr) {
const zeros = arr.filter (arr => arr === 0);
const others = arr.filter (arr => arr !== 0);
return others.concat(zeros);
}
var arr = [false,1,0,1,2,0,1,3,"a"]
function moveZeros(arr){
var zeros = [];
var others = [];
var output;
for (var i=0; i< arr.length; i++){
if (arr[i]===0){
zeros.push(arr[i]);
}else{
others.push(arr[i])
}
}
output = others.concat(zeros);
console.log(output);
}
moveZeros([false,1,0,1,2,0,1,3,"a"]);
This question already has answers here:
Remove duplicate values from JS array [duplicate]
(54 answers)
Closed 8 years ago.
I have the following script that's supposed to uniqualize array:
function uniques(arr) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
for (var j = 0; j < arr[i].length; j++) {
if (a.indexOf(arr[i][j]) === -1 && arr[i][j] !== '') {
a.push(arr[i][j]);
}
}
return a;
}
However, when it receives only one element, it just breaks it into the letters (which is understandable).
Do you know how I make it check if it's receiving only one element and then returns it back?
Thanks!
I'm not sure why you need the nested loop - you only need a single loop if you're processing a non-nested array:
function uniques(arr) {
if (arr.length === 1) { return arr };
var a = [];
for (var i = 0, l = arr.length; i < l; i++) {
if (a.indexOf(arr[i]) === -1) {
a.push(arr[i]);
}
}
return a;
}
DEMO
If you want to process nested arrays, use a recursive function. Here I've used underscore's flatten method as the basis:
function toType(x) {
return ({}).toString.call(x).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
}
function flatten(input, output) {
if (!output) { output = []; }
for (var i = 0, l = input.length; i < l; i++) {
var value = input[i];
if (toType(value) !== 'array' && output.indexOf(value) === -1) {
output.push(value);
} else {
flatten(value, output);
}
}
return output.sort(function (a, b) { return a - b; });
};
var arr = [1, 2, 3, [[4]], [10], 5, 1, 3];
flatten(arr); // [ 1, 2, 3, 4, 5, 10 ]
DEMO
I think the solution is this:
function uniques(arr) {
if (arr.length > 1) {
var a = [];
for (var i=0, l=arr.length; i<l; i++)
for (var j = 0; j < arr[i].length; j++) {
if (a.indexOf(arr[i][j]) === -1 && arr[i][j] !== '') {
a.push(arr[i][j]);
}
}
return a;
}
else
{
return arr;
}
}
What you're trying to do is a linear search on the created matrix for each item in the original one.
The solution below will accomplish this, but at a great cost. If your original matrix is 50x50 with unique values in each cell, it will take you 50^3 (=125000) loops to exit the function.
The best technique to search, in programming science, takes O(log(N)) that means that if you'll use it on your problem it will take log(50^2) (=11) loops.
function uniques(arr) {
var items = [];
var a = arr.map(function(row, i) {
return row.map(function(cell, j) {
if (items.indexOf(cell) >= 0) {
items.push(cell);
return cell;
}
});
});
}
I have several numbers in an array
var numArr = [1, 3, 5, 9];
I want to cycle through that array and multiply every unique 3 number combination as follows:
1 * 3 * 5 =
1 * 3 * 9 =
1 * 5 * 9 =
3 * 5 * 9 =
Then return an array of all the calculations
var ansArr = [15,27,45,135];
Anyone have an elegant solution? Thanks in advance.
A general-purpose algorithm for generating combinations is as follows:
function combinations(numArr, choose, callback) {
var n = numArr.length;
var c = [];
var inner = function(start, choose_) {
if (choose_ == 0) {
callback(c);
} else {
for (var i = start; i <= n - choose_; ++i) {
c.push(numArr[i]);
inner(i + 1, choose_ - 1);
c.pop();
}
}
}
inner(0, choose);
}
In your case, you might call it like so:
function product(arr) {
p = 1;
for (var i in arr) {
p *= arr[i];
}
return p;
}
var ansArr = [];
combinations(
[1, 3, 5, 7, 9, 11], 3,
function output(arr) {
ansArr.push(product(arr));
});
document.write(ansArr);
...which, for the given input, yields this:
15,21,27,33,35,45,55,63,77,99,105,135,165,189,231,297,315,385,495,693
I think this should work:
var a = [1, 3, 5, 9];
var l = a.length;
var r = [];
for (var i = 0; i < l; ++i) {
for (var j = i + 1; j < l; ++j) {
for (var k = j + 1; k < l; ++k) {
r.push(a[i] * a[j] * a[k]);
}
}
}
Edit
Just for my own edification, I figured out a generic solution that uses loops instead of recursion. It's obvious downside is that it's longer thus slower to load or to read. On the other hand (at least on Firefox on my machine) it runs about twice as fast as the recursive version. However, I'd only recommend it if you're finding combinations for large sets, or finding combinations many times on the same page. Anyway, in case anybody's interested, here's what I came up with.
function combos(superset, size) {
var result = [];
if (superset.length < size) {return result;}
var done = false;
var current_combo, distance_back, new_last_index;
var indexes = [];
var indexes_last = size - 1;
var superset_last = superset.length - 1;
// initialize indexes to start with leftmost combo
for (var i = 0; i < size; ++i) {
indexes[i] = i;
}
while (!done) {
current_combo = [];
for (i = 0; i < size; ++i) {
current_combo.push(superset[indexes[i]]);
}
result.push(current_combo);
if (indexes[indexes_last] == superset_last) {
done = true;
for (i = indexes_last - 1; i > -1 ; --i) {
distance_back = indexes_last - i;
new_last_index = indexes[indexes_last - distance_back] + distance_back + 1;
if (new_last_index <= superset_last) {
indexes[indexes_last] = new_last_index;
done = false;
break;
}
}
if (!done) {
++indexes[indexes_last - distance_back];
--distance_back;
for (; distance_back; --distance_back) {
indexes[indexes_last - distance_back] = indexes[indexes_last - distance_back - 1] + 1;
}
}
}
else {++indexes[indexes_last]}
}
return result;
}
function products(sets) {
var result = [];
var len = sets.length;
var product;
for (var i = 0; i < len; ++i) {
product = 1;
inner_len = sets[i].length;
for (var j = 0; j < inner_len; ++j) {
product *= sets[i][j];
}
result.push(product);
}
return result;
}
console.log(products(combos([1, 3, 5, 7, 9, 11], 3)));
A recursive function to do this when you need to select k numbers among n numbers. Have not tested. Find if there is any bug and rectify it :-)
var result = [];
foo(arr, 0, 1, k, n); // initial call
function foo(arr, s, mul, k, n) {
if (k == 1) {
result.push(mul);
return;
}
var i;
for (i=s; i<=n-k; i++) {
foo(arr, i+1, mul*arr[i], k-1, n-i-1);
}
}
This is a recursive function.
First parameter is array arr.
Second parameter is integer s. Each call calculates values for part of the array starting from index s. Recursively I am increasing s and so array for each call is recursively becoming smaller.
Third parameter is the value that is being calculated recursively and is being passed in the recursive call. When k becomes 1, it gets added in the result array.
k in the size of combination desired. It decreases recursively and when becomes 1, output appended in result array.
n is size of array arr. Actually n = arr.length
var create3Combi = function(array) {
var result = [];
array.map(function(item1, index1) {
array.map(function(item2, index2) {
for (var i = index2 + 1; i < array.length; i++) {
var item3 = array[i];
if (item1 === item2 || item1 === item3 || item2 === item3 || index2 < index1) {
continue;
}
result.push([item1, item2, item3]);
}
});
});
return result;
};
var multiplyCombi = function(array) {
var multiply = function(a, b){
return a * b;
};
var result = array.map(function(item, index) {
return item.reduce(multiply);
});
return result;
}
var numArr = [1, 3, 5, 9];
// create unique 3 number combination
var combi = create3Combi(numArr); //[[1,3,5],[1,3,9],[1,5,9],[3,5,9]]
// multiply every combination
var multiplyResult = multiplyCombi(combi); //[15,27,45,135];
https://github.com/dankogai/js-combinatorics
Found this library. Tested to be working. Below is from the library document:
var Combinatorics = require('js-combinatorics');
var cmb = Combinatorics.combination(['a','b','c','d'], 2);
while(a = cmb.next()) console.log(a);
// ["a", "b"]
// ["a", "c"]
// ["a", "d"]
// ["b", "c"]
// ["b", "d"]
// ["c", "d"]
Using node, you can do this pretty easily using a library. First install bit-twiddle using npm:
npm install bit-twiddle
Then you can use it in your code like this:
//Assume n is the size of the set and k is the size of the combination
var nextCombination = require("bit-twiddle").nextCombination
for(var x=(1<<(k+1))-1; x<1<<n; x=nextCombination(x)) {
console.log(x.toString(2))
}
The variable x is a bit-vector where bit i is set if the ith element is contained in the combination.