I'm trying to make a Cartesian product between sub-arrays of a 2D array.
My 2dArray is for ex like this: var matrix = [[1,2,3], [4,5], [6,7,8],[9,10,11]];, but it can have variable number of arrays.
The function that i use is:
function cartesianProductOf() {
return Array.prototype.reduce.call(arguments, function(a, b) {
var ret = [];
a.forEach(function(a) {
b.forEach(function(b) {
ret.push(a.concat([b]));
});
});
return ret;
}, [[]]);
}
I tried to use the function like: cartesianProductOf(matrix) but this does not return any result.
My problem is how to give sub-arrays as parameter for this function? How to split the 2d array in sub-arrays or how to modify the function to work for my case?
Does anyone know how to solve this problem?
Update:
http://jsfiddle.net/XHEJt/10/
var matrix = [[1,2,3], [4,5], [6,7,8],[9,10,11]];
console.log(cartesianProductOf([1,2,3], [4,5], [6,7,8],[9,10,11]));
//the following line does not produce the same output
console.log(cartesianProductOf(matrix));
function cartesianProductOf() {
return Array.prototype.reduce.call(arguments, function(a, b) {
var ret = [];
a.forEach(function(a) {
b.forEach(function(b) {
ret.push(a.concat([b]));
});
});
return ret;
}, [[]]);
}
While you are asking about a function call with parameters (which works) and with an array (which does not work), you could insert a check, if arguments.length is equal to one, and then take the first element of arguments as value for reducing.
return Array.prototype.reduce.call(arguments.length === 1
? arguments[0]
: arguments, function(a, b) {
// ...
Related
I am learning map & reduce, but am having a hard time understanding how to utilize these methods to tackle problems.
For example,
Create a function that takes a number and returns an array of strings containing the number cut off at each digit.
420 should return ["4", "42", "420"]
My old Approach:
function createArrayOfTiers(num) {
var numArr = num.toString().split('');
var output = [];
for(var i = numArr.length-1; i>=0; i--) {
output.unshift(numArr.join('');
numArr.pop();
}
return output;
}
Attempt to use map-reduce combination:
function createArrayOfTiers(num) {
var numArr = num.toString().split('');
return numArr.map(function(element) {
var newElement = numArr.reduce(function(acc, val) {
return acc + val;
});
numArr.splice(element, 1);
return newElement;
});
}
You have used two loops, but apparently it can be done just with one.
function n(num) {
let res = (""+num).split('').map((_,i) => (""+num).slice(0, i+1));
return res;
}
console.log(n(420));
console.log(n(13579));
One-liner.
const n = num => (""+num).split('').map((_,i) => (""+num).slice(0, i+1));
console.log(n(420));
console.log(n(13579));
As others noted, that this problem doesn't seem to be the best use case of the map and reduce functions.
map function provides the element, index and array information in the parameters. Making use of these you can iterate on the elements you need to apply the reduce function.
Statement var arrayToIterate = arr.slice(0,i+1); helps to achieve the above mentioned array to iterate.
Complete Code:
function createArrayOfTiers(num) {
var numArr = num.toString().split('');
return numArr.map(function(element, i, arr) {
var arrayToIterate = arr.slice(0,i+1);
var newElement = arrayToIterate.reduce(function(acc, val) {
return acc + val;
},"");
return newElement;
});
}
var result = createArrayOfTiers(420);
console.log(result);
I don't think these are good uses-cases of map or reduce, but here goes :
var numArr = [4,2,0];
var result = numArr.map(e => numArr.join('')) // now ["420", "420", "420"]
.map((arr, i) => arr.substring(0, i+1)) // now ["4", "42", "420"]
console.log(result);
We first replace every element of the array by the whole (unmodified) array joined into a string, then substring each of these strings based on their position in the outer array.
There's a reduction hidden in there, although not using reduce : join reduces [4, 2, 0] to "420".
I am learning map & reduce, but am having a hard time understanding how to utilize these methods to tackle problems.
Mapping associates to each value of the source array a new value provided by a mapping function : if you have an [x, y, z] array, a mapping function f(x)=x+1, the result of mapping the array with the function will be [x+1, y+1, z+1].
I believe reduction was meant to "reduce" an array to a primitive type, although I might be mistaken. If you have an [x, y, z] array and reduce it with the addition operation, the result will be x+y+z.
I would like to use reduce on an object with values as strings. If that value doesn't contain the target letter than push that value into an array.
For example:
var animals = {a: 'pig', b: 'pony', c:'possum'};
useReduce(animals, "i"); // returns ['pony', 'possum'];
This is what I have so far, but I'm getting an error:
var useReduce = function(obj, target) {
obj.reduce(function(previousValue, currentValue, key, obj) {
if (currentValue.indexOf(target) === -1) {
previousValue.push(currentValue);
};
}, []);
return previousValue;
};
You can convert the object into an array of keys, then you can reduce. Additionally, previousValue relies on the previous call's return value. You forgot to return inside the reduce.
function useReduce(obj, target) {
return Object.keys(obj).reduce((previousValue, key) => {
if (obj[key].indexOf(target) === -1) previousValue.push(key);
return previousValue;
}, []);
}
As those who have commented have suggested, reduce is an array method, not an object method.
It looks like you are trying to filter the array of objects by certain criteria. Here is one way to accomplish that based on your example using Array.prototype.filter.
This function will return an array of objects only if none of the characters in the name property match the second argument (in this case, i).
var animals = [{name: 'pig'}, {name: 'pony'}, {name:'possum'}];
useReduce(animals, 'i');
function useReduce(arr, str) {
return arr.filter(function(obj) {
if (obj.name.match(str)) {
return false;
} else {
return true;
}
}
}
// returns [{name: 'pony'}, {name:'possum'}];
As an alternative to the answers posted here I just wanted to point out how you can solve this using a functional library, for example with Ramda you can do
const animals = {a: 'pig', b: 'pony', c:'possum'}
const noLetter = R.curry((letter, target) => {
return R.compose(R.reject(R.contains(letter)), R.values)(target)
})
noLetter('i', animals) // ["pony", "possum"]
const noLetterI = noLetter('i')
noLetterI(animals) // ["pony", "possum"]
Example:
console.log(f(['12dh', '8-4', '66']))
//output should be => ['8-4', '66', '12dh']
You can do this very easily with sort and reverse.
var array = ['12dh', '8-4', '66'];
var sorted = array.sort().reverse();
console.log(sorted);
You can also wrap it in a function.
function sortReverse(array){
return array.sort().reverse();
}
Also if you're concerned about performance you can pass a custom comparison function to sort:
array.sort(function(a,b){
return a < b;
});
This could be quicker when dealing with larger arrays, because it doesn't have to reverse after sorting.
To filter anything that doesn't start with a number:
array.filter(function(str){
return !isNaN(str.charAt(0));
}).sort().reverse();
You can do something like that:
var array = ['12dh', '8-4', '66'];
array.sort(function (a, b) {
if (a > b) {
return -1;
}
if (a < b) {
return 1;
}
return 0;
});
I hope that helps :D
I have following code:
filters = [
{
"see":false,
"make":true,
"means":true,
},
{
"less":false,
"up3":false,
"up6":false,
"all":true,
"more":false,
"var":false
},
{
"one":false,
"small":true,
"medium":false,
"large":false
}
];
function cartesianProductOf() {
return _.reduce(arguments, function(a, b) {
return _.flatten(_.map(a, function(x) {
return _.map(b, function(y) {
return x.concat([y]);
});
}), true);
}, [ [] ]);
}
function cleaning(collection){
var r = [];
_.each(collection,function(element,index){
r[index] = [];
if(_.isObject(element)){
r[index] = _.map(element,function(val,key){
if(val) return key;
});
}
r[index] = _.compact(r[index]);
});
return r;
}
// cleaning is producing following array
// [["make","means"],["all"],["small"]]
clean = cleaning(filters);
prod = cartesianProductOf(clean);
$('#result').append(JSON.stringify( prod ));
I'm expecting result along the lines:[["make","all","small"], ["means","all","small"]]
but I'm getting [[["make","means"]],[["all"]],[["small"]]] instead.
The Cartesian Product Algorithm is from here: Cartesian product of multiple arrays in JavaScript
here is my fiddle: https://jsfiddle.net/NFSfs/17/
Any Idea would be appreciated.
In short:
just change to
prod = cartesianProductOf.apply(null, clean);
Where was mistake:
The answer is very simple, you stuck with classic dynamic language problem with types, cartesianProductOf is waiting array in "arguments" that mean all arrays should be passed in parenthesis delimited by comma:
cartesianProductOf(["make","means"],["all"],["small"])
but you are passing only one argument that is list of lists
cartesianProductOf([["make","means"],["all"],["small"]])
and function does exactly it should, return the initial array because of cartesian product of one array is that array
Can any one explain whats going on in this JavaScript code? I do not understand the part where the i.reduce is passed with [] as an initial value:
function longestString(i) {
// It will be an array like (['big',[0,1,2,3,4],'tiny'])
// and the function should return the longest string in the array
// This should flatten an array of arrays
var r = i.reduce(function(a, b) {
return a.concat(b);
}, []);
// This should fetch the longest in the flattened array
return r.reduce(function (a, b)
{
return a.length > b.length ? a : b;
});
}
The initial value in a reduce is an accumulator. If for example if i is [[1],[2],[3]] then the reduce statement is equivalent to:
r = [];
r = r.concat([1]);
r = r.concat([2]);
r = r.concat([3]);
In each step of the reduce the function must be called on two arguments. In the first step there must be some initial value. You can't call .concat on nothing so you start with an empty array.