I have the following array as an example;
let arr = [['red','blue','pink],['dog','cat','bird'],['loud', 'quiet']]
I need to write a generalized function that prints all combinations of one word from the first vector, one word from the second vector, etc. I looked up some codes on here but they are all recursion or working only with the specific array. How can I write this code without recursion?
let allComb = function(arr) {
if (arr.length == 1) {
return arr[0];
} else {
let result = [];
let arrComb = allComb(arr.slice(1));
for (let i = 0; i < arrComb.length; i++) {
for (let j = 0; j < arr[0].length; j++) {
result.push(arr[0][j] + ' ' + arrComb[i]);
}
}
return result;
}
}
allComb(arr)
This version uses a single increment per cycle technique with no recursion.
let arr = [
['red', 'blue', 'pink'],
['dog', 'cat', 'bird'],
['loud', 'quiet']
];
function allComb(arr) {
var total = 1;
var current = [];
var result = [];
for (var j = 0; j < arr.length; j++) {
total *= arr[j].length;
current[j] = 0;
}
for (var i = 0; i < total; i++) {
var inc = 1;
result[i] = "";
for (var j = 0; j < arr.length; j++) {
result[i] += arr[j][current[j]] + ' ';
if ((current[j] += inc) == arr[j].length)
current[j] = 0;
else
inc = 0;
}
}
return (result);
}
console.log(allComb(arr));
You may do as follows;
var arr = [['red','blue','pink'],['dog','cat','bird'],['loud', 'quiet']],
res = arr.reduce((p,c) => p.reduce((r,x) => r.concat(c.map(y => x + " " + y)),[]));
console.log(res);
So I need few arrays:
array 1 = [1,9,17,25,33,41];
array 2 = [2,10,18,26,34,42];
etc.
So each array adds up 8 to the last item.
But, I need to generate this dynamically (using functions in JavaScript).
var initValue = 5;
var diff = 8;
var len = 5;
function makeDiffArray(initValue, diff, len) {
for (var i = 0, arr = []; i < len; i++) {
arr.push(initValue);
initValue += diff;
}
return arr;
}
console.log(makeDiffArray(initValue, diff, len));
Something like this?
for(var i = 1; i<10;i++){
eval("var array" + i + " = [" + i + "];");
for(var j = 1; j<10; j++){
eval("array" + i + ".push(array" + i + "[array" + i + ".length] + 8);");
}
}
You can also try dynamic variable names
var arrayCount = 2;
var initValue = 5;
var diff = 8;
var len = 5;
for(var i=1; i<=arrayCount; i++) {
window['array'+i] = makeAnArray(i,diff,len);
alert(window['array'+i]);
}
function makeAnArray(initValue) {
var anArray = [];
for (var j = 0, init = initValue; j < len; j++) {
anArray.push(init);
init += diff;
}
return anArray;
}
I know this has already been accepted, just wanted to add the ES6 version here.
let [init, diff, len] = [5, 8, 5], tmp = init;
let arr = Array(len).fill(init).map( (x, i) => (i) ? tmp += diff : x );
console.log(arr)
I am getting NaN and Infinity in getting the max value of my JSON Array object.
I am trying to append the properties of a GeoJSOn data from other JSON.
Here's the JSFiddle for reference.
The snippet:
$.map(data, function (e) {
var dev_id = e.dev_id;
var data = e.data;
for (var j = 0; j < data.length; j++) {
var rainVal = parseFloat(data[j].rain_value);
arr[j] = parseFloat(rainVal);
}
var max = Math.max.apply(Math, arr) * 4;
console.log(dev_id + " " + max)
for (var k = 0; k < len; k++) {
jsonObj_device_id = jsonObj.features[k].properties["device_id"];
if (jsonObj_device_id === dev_id) {
var nameR = "rain_intensity";
var rainValue = max;
jsonObj.features[k].properties[nameR] = rainValue;
}
}
});
There are cases in your code, where in the AJAX response, you are either not getting the Data i.e. e.data or if you get the data you are not getting rain_value. If you do not get e.data first time, you will get Infinity logged on your console because var max = Math.max.apply(Math, []) results in -Infinity. If you do not get rain_value then parseFloat would give you NaN.
Validate the API response before such operations. Something like this.
var dev_id = e.dev_id;
var data = e.data;
var max = 0, r;
var arr = [];
if(data) {
for (var j = 0; j < data.length; j++) {
r = data[j].rain_value || 0;
arr[j] = parseFloat(r);
}
}
if(arr.length) {
max = Math.max.apply(Math, arr) * 4;
}
console.log(dev_id + " " + max);
Here is a working demo
var rainVal = parseFloat(data[j].rain_value);
if (!rainVal) // check 1
rainVal = 0;
arr[j] = parseFloat(rainVal);
}
var max = 0;
if (arr) // check 2
{
maxBeforeTested = Math.max.apply(Math, arr) * 4;
if (isFinite(maxBeforeTested)) //check 3
max = maxBeforeTested;
else
console.log("Had an infinite value here.");
}
console.log("Cleaned output: " + dev_id + " " + max)
Basically, you needed some checks, I have added comments as "Check".
Any number greater than 1.797693134862315E+308 is infinity. Use isFinite() to check.
NaN means not a number value, you can check that using isNaN() or simply if()
What is a fast and simple implementation of interleave:
console.log( interleave([1,2,3,4,5,6] ,2) ); // [1,4,2,5,3,6]
console.log( interleave([1,2,3,4,5,6,7,8] ,2) ); // [1,5,2,6,3,7,4,8]
console.log( interleave([1,2,3,4,5,6] ,3) ); // [1,3,5,2,4,6]
console.log( interleave([1,2,3,4,5,6,7,8,9],3) ); // [1,4,7,2,5,8,3,6,9]
This mimics taking the array and splitting it into n equal parts, and then shifting items off the front of each partial array in sequence. (n=2 simulates a perfect halving and single shuffle of a deck of cards.)
I don't much care exactly what happens when the number of items in the array is not evenly divisible by n. Reasonable answers might either interleave the leftovers, or even "punt" and throw them all onto the end.
function interleave( deck, step ) {
var copyDeck = deck.slice(),
stop = Math.floor(copyDeck.length/step),
newDeck = [];
for (var i=0; i<step; i++) {
for (var j=0; j<stop; j++) {
newDeck[i + (j*step)] = copyDeck.shift();
}
}
if(copyDeck.length>0) {
newDeck = newDeck.concat(copyDeck);
}
return newDeck;
}
It could be done with a counter instead of shift()
function interleave( deck, step ) {
var len = deck.length,
stop = Math.floor(len/step),
newDeck = [],
cnt=0;
for (var i=0; i<step; i++) {
for (var j=0; j<stop; j++) {
newDeck[i + (j*step)] = deck[cnt++];
}
}
if(cnt<len) {
newDeck = newDeck.concat(deck.slice(cnt,len));
}
return newDeck;
}
And instead of appending the extras to the end, we can use ceil and exit when we run out
function interleave( deck, step ) {
var copyDeck = deck.slice(),
stop = Math.ceil(copyDeck.length/step),
newDeck = [];
for (var i=0; i<step; i++) {
for (var j=0; j<stop && copyDeck.length>0; j++) {
newDeck[i + (j*step)] = copyDeck.shift();
}
}
return newDeck;
}
can i has prize? :-D
function interleave(a, n) {
var i, d = a.length + 1, r = [];
for (i = 0; i < a.length; i++) {
r[i] = a[Math.floor(i * d / n % a.length)];
}
return r;
}
according to my tests r.push(... is faster than r[i] = ... so do with that as you like..
note this only works consistently with sets perfectly divisible by n, here is the most optimized version i can come up with:
function interleave(a, n) {
var i, d = (a.length + 1) / n, r = [a[0]];
for (i = 1; i < a.length; i++) {
r.push(a[Math.floor(i * d) % a.length]);
}
return r;
}
O(n-1), can anyone come up with a log version? to the mathmobile! [spinning mathman logo]
Without for loops (I've added some checkup for the equal blocks):
function interleave(arr, blocks)
{
var len = arr.length / blocks, ret = [], i = 0;
if (len % 1 != 0) return false;
while(arr.length>0)
{
ret.push(arr.splice(i, 1)[0]);
i += (len-1);
if (i>arr.length-1) {i = 0; len--;}
}
return ret;
}
alert(interleave([1,2,3,4,5,6,7,8], 2));
And playground :) http://jsfiddle.net/7tC9F/
how about functional with recursion:
function interleave(a, n) {
function f(a1, d) {
var next = a1.length && f(a1.slice(d), d);
a1.length = Math.min(a1.length, d);
return function(a2) {
if (!a1.length) {
return false;
}
a2.push(a1.shift());
if (next) {
next(a2);
}
return true;
};
}
var r = [], x = f(a, Math.ceil(a.length / n));
while (x(r)) {}
return r;
}
Phrogz was pretty close, but it didn't interleave properly. This is based on that effort:
function interleave(items, parts) {
var len = items.length;
var step = len/parts | 0;
var result = [];
for (var i=0, j; i<step; ++i) {
j = i
while (j < len) {
result.push(items[j]);
j += step;
}
}
return result;
}
interleave([0,1,2,3], 2); // 0,2,1,3
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 2) // 0,6,1,7,2,8,3,9,4,10,5,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 3) // 0,4,8,1,5,9,2,6,10,3,7,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 4) // 0,3,6,9,1,4,7,10,2,5,8,11
interleave([0,1,2,3,4,5,6,7,8,9,10,11], 5) // 0,2,4,6,8,10,1,3,5,7,9,11
Since I've been pushed to add my own answer early (edited to fix bugs noted by RobG):
function interleave(items,parts){
var stride = Math.ceil( items.length / parts ) || 1;
var result = [], len=items.length;
for (var i=0;i<stride;++i){
for (var j=i;j<len;j+=stride){
result.push(items[j]);
}
}
return result;
}
try this one:
function interleave(deck, base){
var subdecks = [];
for(count = 0; count < base; count++){
subdecks[count] = [];
}
for(var count = 0, subdeck = 0; count < deck.length; count++){
subdecks[subdeck].push(deck[count]);
subdeck = subdeck == base - 1? 0 : subdeck + 1;
}
var newDeck = [];
for(count = 0; count < base; count++){
newDeck = newDeck.concat(subdecks[count]);
}
return newDeck;
}