Flatten at array using Javascript - javascript

The problem is to try and remove nested arrays:
steamrollArray([1, [2], [3, [[4]]]]); // should return [1, 2, 3, 4]
I have tried this but the recursion is failing when a nested array appears.
function checkElement(el) {
if (Array.isArray(el)) {
if (el.length === 1) {
return checkElement(el[0]);
} else {
for (var i=0; i < el.length; i++){
checkElement(el[i]);
}
}
} else {
return (el);
}
}
function steamrollArray(arr) {
var finalArr = [];
for (var i=0; i < arr.length; i++){
finalArr.push(checkElement(arr[i]));
}
return (finalArr);
}

A proposal for the first part:
You could change the return value to array and use concat instead of push.
function checkElement(el) {
// collect the values of the checked array
var temp = [];
if (Array.isArray(el)) {
if (el.length === 1) {
return checkElement(el[0]);
} else {
for (var i = 0; i < el.length; i++) {
// collect the values
temp = temp.concat(checkElement(el[i]));
}
// return flat values
return temp;
}
} else {
return el;
}
}
// this can be shorten to
function steamrollArray(arr) {
return checkElement(arr);
}
console.log(steamrollArray([1, [2], [3, [[4]]]]));
Part two, a bit shorter:
function steamrollArray(arr) {
return arr.reduce(function flat(r, a) {
return Array.isArray(a) && a.reduce(flat, r) || r.concat(a);
}, []);
}
console.log(steamrollArray([1, [2], [3, [[4]]]]));

You could use reduce:
function flatten( array ){
return array.reduce( function (a, b){
return a.concat( Array.isArray(b) ? flatten(b) : b );
}, [] );
}

I think this would be the funniest way to do this and also it's one line no more. Also it leaves extraction to native code which is much faster than Scripting.
var nestedArray = [1, [2], [3, [[4]]]];
var flatten = nestedArray.toString().split(',').map(Number);
console.log(flatten);

You can use recursion like this:
function flatten(array) {
var flat = []; //The result array
//An IIFE that will perform the recursion,
//is equivalent to: function rec(param) {.....}; rec(param);
(function rec(a) {
//For each element in the array:
//If the element is an array then call the 'rec' function.
//Else, push it to the result array.
//I used the conditional (ternary) operator (condition ? expr1 : expr2 )
for(var i in a) Array.isArray(a[i]) ? rec(a[i]) : flat.push(a[i]);
})(array);//Initiate the recursion with the main array
return flat;//Return the final result
};
var a = [1, [2], [3, [[4]]]];
function flatten(array) {
var flat = [];
(function rec(a) {
for(var i in a) Array.isArray(a[i]) ? rec(a[i]) : flat.push(a[i]);
})(array);
return flat;
};
console.log(flatten(a));

Using a generator function allows you to efficiently iterate through nested array elements without allocating unnecessary memory. If you really need the flattened array itself, use [...iterable] or Array.from(iterable):
function* deepIterate(array) {
for (a of array) Array.isArray(a) ? yield* deepIterate(a) : yield a;
}
// Iterate through flattened array:
for (a of deepIterate([1,[2,[3]]])) console.log(a);
// Flatten array:
var flat = Array.from(deepIterate([1,[2,[3]]]));
console.log(flat);

You can't just return the values, or it wouldn't work when you have arrays of length > 1.
Here's a solution:
function steamrollArray(arr, flattened) {
if (!flattened) flattened = [];
for (var i=0; i < arr.length; i++){
if (Array.isArray(arr[i])) {
steamrollArray(arr[i], flattened);
} else {
flattened.push(arr[i]);
}
}
return flattened;
}
console.log(steamrollArray([1, [2], [3, [[4]]]])); // should return [1, 2, 3, 4]

Try This if it work for you
function steamrollArray(unflatenArr) {
var flatenArr = [];
if (Array.isArray(unflatenArr)) {
for (var i = 0; i < unflatenArr.length; i++)
arrFlat(unflatenArr[i], flatenArr);
}
return flatenArr;
}
function arrFlat(arr, refArr) {
if (Array.isArray(arr)) {
for (var i = 0; i < arr.length; i++) {
arrFlat(arr[i], refArr);
}
}
else {
refArr.push(arr);
}
}

A simpler solution without using any recursion is by using splice method of Arrays. It works for any level of nesting.
function flattenArray(arr){
for(var i=0;i<arr.length;i++){
if(arr[i] instanceof Array){
Array.prototype.splice.apply(arr,[i,1].concat(arr[i]))
i--;
}
}
return arr;
}

Try this:
function steamrollArray(unflatenArr){
return eval("["+(JSON.stringify(unflatenArr).replace(/\[/g,'').replace(/\]/g,''))+"]")
}
steamrollArray([1, [2], [3, [[4]]]]);

Related

How do I recursively call a prototype function inside itself while looping an array in JavaScript?

I'm creating a polyfill of Array.flat() method, however, I'm facing issues while calling the function within itself after checking that the looped element is an array and thats need to be flattened further. When a write a code that is not prototypal, the flattening is proper, however when I try to create a prototype function, I'm unable to get the flattened array. I'm pretty sure that the issue is related with the 'this' keyword. Please have a look at my code.
Here is the code
let arrayFlat = [1, 2, 3, [4, 5, 6, [7, 8, [9]], 10, [11, 12]], [13, [14, 15]]];
const flatArray = (array) => {
let output = [];
const flatten = (array) => {
for (let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flatten(array[i]);
} else {
output.push(array[i]);
}
}
return output;
};
return flatten(array);
};
Array.prototype.myFlat = function () {
let output = [];
for (let i = 0; i < this.length; i++) {
if (Array.isArray(this[i])) {
console.log(this[i]);
this[i].myFlat();
} else {
output.push(this[i]);
}
}
return output;
};
In your first piece of code, you create a single output array. When you recursively call flatten, the code is always pushing to the exact same output array, which is in the closure of flatten. Then once everything is done, you return that array.
In the second code, you create a new array every time you recurse. Each recursion will create an array, flatten itself, and then return that new array. But the return value is ignored, so these values don't go anywhere.
You have a few options
Make the code basically identical to your first one, with an internal function for doing the recursion, and a closure variable used by all:
Array.prototype.myFlat = function () {
let output = [];
const flatten = (array) => {
for (let i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
flatten(array[i]);
} else {
output.push(array[i]);
}
}
return output;
};
return flatten(this);
}
Pass the output array as a parameter when you recurse:
// VVVVVV--- added parameter
Array.prototype.myFlat = function (output = []) {
for (let i = 0; i < this.length; i++) {
if (Array.isArray(this[i])) {
this[i].myFlat(output); // <---- forward the array along
} else {
output.push(this[i]);
}
}
return output;
};
Continue having separate arrays, but then merge them together as the stack unwinds:
Array.prototype.myFlat = function () {
let output = [];
for (let i = 0; i < this.length; i++) {
if (Array.isArray(this[i])) {
output.push(...this[i].myFlat()); // <---- added output.push
} else {
output.push(this[i]);
}
}
return output;
};
I am a strong proponent of keeping classes as thin as possible, wrapping functional interfaces wherever possible -
function myFlat(t) {
return Array.isArray(t)
? t.reduce((r, v) => r.concat(myFlat(v)), [])
: [t]
}
Array.prototype.myFlat = function() { return myFlat(this) }
console.log([1,[2,[3],4],[[5]],6,[[[7]]]].myFlat())
// [ 1, 2, 3, 4, 5, 6, 7 ]

Get every nth element from array and map/push to new arrays [duplicate]

I've got an array of arrays, something like:
[
[1,2,3],
[1,2,3],
[1,2,3],
]
I would like to transpose it to get the following array:
[
[1,1,1],
[2,2,2],
[3,3,3],
]
It's not difficult to programmatically do so using loops:
function transposeArray(array, arrayLength){
var newArray = [];
for(var i = 0; i < array.length; i++){
newArray.push([]);
};
for(var i = 0; i < array.length; i++){
for(var j = 0; j < arrayLength; j++){
newArray[j].push(array[i][j]);
};
};
return newArray;
}
This, however, seems bulky, and I feel like there should be an easier way to do it. Is there?
output = array[0].map((_, colIndex) => array.map(row => row[colIndex]));
map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values; it is not invoked for indexes which have been deleted or which have never been assigned values.
callback is invoked with three arguments: the value of the element, the index of the element, and the Array object being traversed. [source]
Many good answers here! I consolidated them into one answer and updated some of the code for a more modern syntax:
One-liners inspired by Fawad Ghafoor and Óscar Gómez Alcañiz
function transpose(matrix) {
return matrix[0].map((col, i) => matrix.map(row => row[i]));
}
function transpose(matrix) {
return matrix[0].map((col, c) => matrix.map((row, r) => matrix[r][c]));
}
Functional approach style with reduce by Andrew Tatomyr
function transpose(matrix) {
return matrix.reduce((prev, next) => next.map((item, i) =>
(prev[i] || []).concat(next[i])
), []);
}
Lodash/Underscore by marcel
function tranpose(matrix) {
return _.zip(...matrix);
}
// Without spread operator.
function transpose(matrix) {
return _.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
}
Even simpler Lodash/Underscore solution by Vigrant
_.unzip(matrix);
Vanilla approach
function transpose(matrix) {
const rows = matrix.length, cols = matrix[0].length;
const grid = [];
for (let j = 0; j < cols; j++) {
grid[j] = Array(rows);
}
for (let i = 0; i < rows; i++) {
for (let j = 0; j < cols; j++) {
grid[j][i] = matrix[i][j];
}
}
return grid;
}
Vanilla in-place ES6 approach inspired by Emanuel Saringan
function transpose(matrix) {
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < i; j++) {
const temp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = temp;
}
}
}
// Using destructing
function transpose(matrix) {
for (var i = 0; i < matrix.length; i++) {
for (var j = 0; j < i; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
}
}
}
here is my implementation in modern browser (without dependency):
transpose = m => m[0].map((x,i) => m.map(x => x[i]))
You could use underscore.js
_.zip.apply(_, [[1,2,3], [1,2,3], [1,2,3]])
shortest way with lodash/underscore and es6:
_.zip(...matrix)
where matrix could be:
const matrix = [[1,2,3], [1,2,3], [1,2,3]];
Neat and pure:
[[0, 1], [2, 3], [4, 5]].reduce((prev, next) => next.map((item, i) =>
(prev[i] || []).concat(next[i])
), []); // [[0, 2, 4], [1, 3, 5]]
Previous solutions may lead to failure in case an empty array is provided.
Here it is as a function:
function transpose(array) {
return array.reduce((prev, next) => next.map((item, i) =>
(prev[i] || []).concat(next[i])
), []);
}
console.log(transpose([[0, 1], [2, 3], [4, 5]]));
Update.
It can be written even better with spread operator:
const transpose = matrix => matrix.reduce(
($, row) => row.map((_, i) => [...($[i] || []), row[i]]),
[]
)
You can do it in in-place by doing only one pass:
function transpose(arr,arrLen) {
for (var i = 0; i < arrLen; i++) {
for (var j = 0; j <i; j++) {
//swap element[i,j] and element[j,i]
var temp = arr[i][j];
arr[i][j] = arr[j][i];
arr[j][i] = temp;
}
}
}
Just another variation using Array.map. Using indexes allows to transpose matrices where M != N:
// Get just the first row to iterate columns first
var t = matrix[0].map(function (col, c) {
// For each column, iterate all rows
return matrix.map(function (row, r) {
return matrix[r][c];
});
});
All there is to transposing is mapping the elements column-first, and then by row.
Another approach by iterating the array from outside to inside and reduce the matrix by mapping inner values.
const
transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]];
console.log(transpose(matrix));
If you have an option of using Ramda JS and ES6 syntax, then here's another way to do it:
const transpose = a => R.map(c => R.map(r => r[c], a), R.keys(a[0]));
console.log(transpose([
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
])); // => [[1,5,9],[2,6,10],[3,7,11],[4,8,12]]
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>
If using RamdaJS is an option, this can be achieved in one line: R.transpose(myArray)
Spread syntax should not be used as an alternative to push, it should only be used when you don't want to mutate the existing array.
Algorithm:
For every column, just check if for that column there's a row in the resultant matrix, if there's already a row then simply push the element, else create a new row array and then push.
So, unlike many other solutions above, this solution doesn't create new arrays again and again, instead pushes onto the same array.
Also, take some time to appreciate the use of the Nullish Coalescing Operator.
const
transpose = arr => arr.reduce((m, r) => (r.forEach((v, i) => (m[i] ??= [], m[i].push(v))), m), []),
matrix = [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
console.log(transpose(matrix))
You can achieve this without loops by using the following.
Array
Array.prototype.map
Array.prototype.reduce
Array.prototype.join
String.prototype.split
It looks very elegant and it does not require any dependencies such as jQuery of Underscore.js.
function transpose(matrix) {
return zeroFill(getMatrixWidth(matrix)).map(function(r, i) {
return zeroFill(matrix.length).map(function(c, j) {
return matrix[j][i];
});
});
}
function getMatrixWidth(matrix) {
return matrix.reduce(function (result, row) {
return Math.max(result, row.length);
}, 0);
}
function zeroFill(n) {
return new Array(n+1).join('0').split('').map(Number);
}
Minified
function transpose(m){return zeroFill(m.reduce(function(m,r){return Math.max(m,r.length)},0)).map(function(r,i){return zeroFill(m.length).map(function(c,j){return m[j][i]})})}function zeroFill(n){return new Array(n+1).join("0").split("").map(Number)}
Here is a demo I threw together. Notice the lack of loops :-)
// Create a 5 row, by 9 column matrix.
var m = CoordinateMatrix(5, 9);
// Make the matrix an irregular shape.
m[2] = m[2].slice(0, 5);
m[4].pop();
// Transpose and print the matrix.
println(formatMatrix(transpose(m)));
function Matrix(rows, cols, defaultVal) {
return AbstractMatrix(rows, cols, function(r, i) {
return arrayFill(cols, defaultVal);
});
}
function ZeroMatrix(rows, cols) {
return AbstractMatrix(rows, cols, function(r, i) {
return zeroFill(cols);
});
}
function CoordinateMatrix(rows, cols) {
return AbstractMatrix(rows, cols, function(r, i) {
return zeroFill(cols).map(function(c, j) {
return [i, j];
});
});
}
function AbstractMatrix(rows, cols, rowFn) {
return zeroFill(rows).map(function(r, i) {
return rowFn(r, i);
});
}
/** Matrix functions. */
function formatMatrix(matrix) {
return matrix.reduce(function (result, row) {
return result + row.join('\t') + '\n';
}, '');
}
function copy(matrix) {
return zeroFill(matrix.length).map(function(r, i) {
return zeroFill(getMatrixWidth(matrix)).map(function(c, j) {
return matrix[i][j];
});
});
}
function transpose(matrix) {
return zeroFill(getMatrixWidth(matrix)).map(function(r, i) {
return zeroFill(matrix.length).map(function(c, j) {
return matrix[j][i];
});
});
}
function getMatrixWidth(matrix) {
return matrix.reduce(function (result, row) {
return Math.max(result, row.length);
}, 0);
}
/** Array fill functions. */
function zeroFill(n) {
return new Array(n+1).join('0').split('').map(Number);
}
function arrayFill(n, defaultValue) {
return zeroFill(n).map(function(value) {
return defaultValue || value;
});
}
/** Print functions. */
function print(str) {
str = Array.isArray(str) ? str.join(' ') : str;
return document.getElementById('out').innerHTML += str || '';
}
function println(str) {
print.call(null, [].slice.call(arguments, 0).concat(['<br />']));
}
#out {
white-space: pre;
}
<div id="out"></div>
I found the above answers either hard to read or too verbose, so I write one myself. And I think this is most intuitive way to implement transpose in linear algebra, you don't do value exchange, but just insert each element into the right place in the new matrix:
function transpose(matrix) {
const rows = matrix.length
const cols = matrix[0].length
let grid = []
for (let col = 0; col < cols; col++) {
grid[col] = []
}
for (let row = 0; row < rows; row++) {
for (let col = 0; col < cols; col++) {
grid[col][row] = matrix[row][col]
}
}
return grid
}
Edit: This answer would not transpose the matrix, but rotate it. I didn't read the question carefully in the first place :D
clockwise and counterclockwise rotation:
function rotateCounterClockwise(a){
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[j][n-i-1];
a[j][n-i-1]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[n-j-1][i];
a[n-j-1][i]=tmp;
}
}
return a;
}
function rotateClockwise(a) {
var n=a.length;
for (var i=0; i<n/2; i++) {
for (var j=i; j<n-i-1; j++) {
var tmp=a[i][j];
a[i][j]=a[n-j-1][i];
a[n-j-1][i]=a[n-i-1][n-j-1];
a[n-i-1][n-j-1]=a[j][n-i-1];
a[j][n-i-1]=tmp;
}
}
return a;
}
const transpose = array => array[0].map((r, i) => array.map(c => c[i]));
console.log(transpose([[2, 3, 4], [5, 6, 7]]));
ES6 1liners as :
let invert = a => a[0].map((col, c) => a.map((row, r) => a[r][c]))
so same as Óscar's, but as would you rather rotate it clockwise :
let rotate = a => a[0].map((col, c) => a.map((row, r) => a[r][c]).reverse())
let a = [
[1,1,1]
, ["_","_","1"]
]
let b = rotate(a);
let c = rotate(b);
let d = rotate(c);
console.log(`a ${a.join("\na ")}`);
console.log(`b ${b.join("\nb ")}`);
console.log(`c ${c.join("\nc ")}`);
console.log(`d ${d.join("\nd ")}`);
Yields
a 1,1,1
a _,_,1
b _,1
b _,1
b 1,1
c 1,_,_
c 1,1,1
d 1,1
d 1,_
d 1,_
I think this is slightly more readable. It uses Array.from and logic is identical to using nested loops:
var arr = [
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]
];
/*
* arr[0].length = 4 = number of result rows
* arr.length = 3 = number of result cols
*/
var result = Array.from({ length: arr[0].length }, function(x, row) {
return Array.from({ length: arr.length }, function(x, col) {
return arr[col][row];
});
});
console.log(result);
If you are dealing with arrays of unequal length you need to replace arr[0].length with something else:
var arr = [
[1, 2],
[1, 2, 3],
[1, 2, 3, 4]
];
/*
* arr[0].length = 4 = number of result rows
* arr.length = 3 = number of result cols
*/
var result = Array.from({ length: arr.reduce(function(max, item) { return item.length > max ? item.length : max; }, 0) }, function(x, row) {
return Array.from({ length: arr.length }, function(x, col) {
return arr[col][row];
});
});
console.log(result);
I didn't find an answer that satisfied me, so I wrote one myself, I think it is easy to understand and implement and suitable for all situations.
transposeArray: function (mat) {
let newMat = [];
for (let j = 0; j < mat[0].length; j++) { // j are columns
let temp = [];
for (let i = 0; i < mat.length; i++) { // i are rows
temp.push(mat[i][j]); // so temp will be the j(th) column in mat
}
newMat.push(temp); // then just push every column in newMat
}
return newMat;
}
Since nobody so far mentioned a functional recursive approach here is my take. An adaptation of Haskell's Data.List.transpose.
var transpose = as => as.length ? as[0].length ? [as.reduce((rs, a) => a.length ? (rs.push(a[0]), rs) :
rs, []
), ...transpose(as.map(a => a.slice(1)))] :
transpose(as.slice(1)) :
[],
mtx = [
[1],
[1, 2],
[1, 2, 3]
];
console.log(transpose(mtx))
.as-console-wrapper {
max-height: 100% !important
}
Adding TS version here.
const transpose = <T>(m: Array<Array<T>>): Array<Array<T>> => m[0].map((_, i) => m.map(x => x[i]));
One-liner that does not change given array.
a[0].map((col, i) => a.map(([...row]) => row[i]))
This one, is not only a super efficient one, but a pretty short solution.
Algorithm Time Complexity: O(n log n)
const matrix = [
[1,1,1,1],
[2,2,2,2],
[3,3,3,3],
[4,4,4,4]
];
matrix.every((r, i, a) => (
r.every((_, j) => (
j = a.length-j-1,
[ r[j], a[j][i] ] = [ a[j][i], r[j] ],
i < j-1
)),
i < length-2
));
console.log(matrix);
/*
Prints:
[
[1,2,3,4],
[1,2,3,4],
[1,2,3,4],
[1,2,3,4]
]
*/
The example above will do only 6 iterations.
For bigger matrix, say 100x100 it will do 4,900 iterations, this is 51% faster than any other solution provided here.
The principle is simple, you on only iterate through the upper diagonal half of the matrix, because the diagonal line never changes and the bottom diagonal half being is switched together with the upper one, so there is no reason to iterate through it as well. This way, you save a lot of running time, especially in a large matrix.
function invertArray(array,arrayWidth,arrayHeight) {
var newArray = [];
for (x=0;x<arrayWidth;x++) {
newArray[x] = [];
for (y=0;y<arrayHeight;y++) {
newArray[x][y] = array[y][x];
}
}
return newArray;
}
reverseValues(values) {
let maxLength = values.reduce((acc, val) => Math.max(val.length, acc), 0);
return [...Array(maxLength)].map((val, index) => values.map((v) => v[index]));
}

how to print a unique number in a array

The problem is to find the unique number in a array such as [2,2,2,5].
The output should be 5 as it is the 1 unique element in the array.
I have attempted this:
function findUniq(arr) {
var b= arr[0];
var c;
for(var i=0; i<arr.length; i++)
{
if(arr[i]===b )
{
b=arr[i]
}
else
{
c=arr[i];
}
}
return c
console.log(findUniq([3, 5, 3, 3, 3]))
This works fine unless the unique number is the first element in the array. How do I fix this?
You can use indexOf and lastIndexOf to see if a value occurs more than once in the array (if it does, they will be different), and if so, it is not the unique value. Use filter to process the array:
let array = [2,2,2,5];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
array = [5,3,3,3,3];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
array = [4,4,5,4];
console.log(array.filter(v => array.indexOf(v) === array.lastIndexOf(v)));
You can create a recursive function that will take the first element of the array and see if it exists in the rest of it, if it does, it will take the next element and do the same, return the element if it doesn't exist in the rest of the array :
const arr = [3, 3, 3, 5, 3];
const find = arr => {
const [f, ...rest] = arr;
if(rest.includes(f))
return find(rest);
else
return f;
}
const result = find(arr);
console.log(result);
Note that this will return the last element if all of them are the same [3,3,3] will return 3
Try something like this using a set, which only stores unique elements:
var set = new Set(arr);
// count instances of each element in set
result = {};
for(var i = 0; i < a.length; ++i) {
if(!result[arr[i]])
result[arr[i]] = 0;
++result[arr[i]];
}
for (var value in result) {
if (value == 1) {
return value;
}
}
// if there isn't any
return false;
This should work, please tell me if it doesn't.
This is another implementation that is surely less efficient than that of #Nick's, but it is a valid algorithm anyway:
function findUniq(arr) {
var elemCount = new Map();
var uniq = [];
// Initialize elements conts
for (var k of arr.values()) {
elemCount.set(k, 0);
}
// Count elements
for (var k of arr.values()) {
elemCount.set(k, elemCount.get(k) + 1);
}
// Add uniq elements to array
for (var [k, v] of elemCount.entries()) {
if (v === 1) uniq.push(k);
}
return uniq;
}
console.log(findUniq([3, 5, 3, 3, 3]))
if you prefer .reduce over .map for your use case (for performance/etc. reasons):
function existance(data) {
return data.reduce((a, c) => (data.indexOf(c) === data.lastIndexOf(c)) ? a.concat(c) : a, []);
}
console.log(existance([1,1,1,2]));
console.log(existance([1,1,2,3,4,5,5,6,6,6]));

Turning for loop into forEach JavaScript

Working on a function that verifies if each number in an array is true or false and returns the first true number.
Have a working solution with a for loop as follows:
function findElement(arr, func) {
var num;
for (var a = 0; a < arr.length; a++) {
if (func(arr[a])) {
num = arr[a];
return num;
}
}
return num;
}
findElement([1, 3, 5, 8, 9, 10], function(num) {
return num % 2 === 0;
})
// Should return 8
But I'm trying (in order to get my head around forEach better) to convert it into a forEach loop.
This is where I am so far, but I don't see how to actually return the num out of the loop after it's been established that the function result is true:
function findElement(arr, func) {
if (arr.forEach(func) === true) {
return num;
}
}
findElement([1, 2, 3, 4], num => num % 2 === 0);
Not sure how to use forEach but you could use array.prototype.filter:
function findElement(arr, func) {
return arr.filter(func)[0];
}
#cdhowie suggested the use array.prototype.find in order to need the usage of [0].
function findElement(arr, func) {
return arr.find(func);
}
Obviously, that is just a guess because it may raise an error if no item in the array meets the requirements of func.
If you still are looking about use forEach maybe you could do something like this:
function findElement(arr, func) {
matches = []
arr.forEach((item) => {
if (func(item)) {
matches.push(item)
}
});
return matches[0];
}
Or:
function findElement(arr, func) {
match = null
arr.forEach((item) => {
match = (match == null && func(item)) ? item : match
});
return match;
}
Again, you will have to check how to handle the error if no item in the array meets the requirements f your func.
Any of both codes produce
console.log(findElement([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; })))
8
function findElement(arr, func) {
var num;
arr.forEach(function(element) {
if (!num && func(element)) {
num = element;
}
});
return num;
}
For more options you can check this question: how to stop Javascript forEach?
As has already been mentioned, this is not how forEach should be used.
However, you can still get the behavior you want:
function findElement(arr, func) {
var num;
arr.forEach(item =>{
if (func(item)) {
num = item;
// .forEach does not have an early return
// but you can force it to skip elements by removing them
while (true) {
// Remove all elements
var removedItem = arr.shift();
if (removedItem === undefined) {
// All elements removed
break;
}
}
}
return num;
}
This is even mentioned in the documentation
maybe like this
function findElement(arr, func) {
var num = null;
for (var a = 0; a < arr.length && num === null; a++) {
var val = arr[a];
num = func(val) ? val : null;
}
return num;
}
console.log(findElement([1, 3, 5, 8, 9, 10], function(num) {
return num % 2 === 0;
}));
here is your findElement method with foreach
function findElement(arr, func) {
var num = 0;
arr.forEach(function(item){
if (func(item))
return item;
})
return num;
}

recursively putting array elements in their own array

I'm trying to create a function that puts each array element in its own array, recursively.
I think my base case is correct, but my recursive call doesn't appear to be working. any insight?
function ownList(arr){
if (arr.length === 1) {
arr[0] = [arr[0]];
return;
} else {
return arr[0].concat(ownList(arr.slice(1)));
}
}
var arr = [1,2,3]
console.log(ownList(arr))// returns []
//should return [[1],[2],[3]]
Here I'm trying to put each pair in it's own list (recursive only). This code below is correct (update)
function ownListPair(arr){
if (arr.length === 0)
return arr;
else if(arr.length === 1)
return [[arr[0], 0]];
else
return [[arr[0], arr[1]]].concat(ownListPair(arr.slice(2)));
}
// var arr = [3,6,8,1,5]
var arr = [2,7,8,3,1,4]
//returns [ [ 2, 7 ], [ 8, 3 ], [ 1, 4 ]]
console.log(ownListPair(arr))
I prefer this solution for several reasons:
function ownList(a) {
return a.length == 0
? []
: [[a[0]]].concat(ownList(a.slice(1)))
}
It's shorter and more concise
It works for empty arrays as well
The actual wrapping happens only once in the last line. Treating length == 1 separately -- as suggested by others -- is not necessary.
It would more appropriate to make a length of 0 be the null case. Then you just have to get the brackets right. The thing on the left side of the concat should be an array consisting of the array containing the first element.
function ownList(arr) {
return arr.length ? [[arr[0]]].concat(ownList(arr.slice(1))) : [];
}
Here's an alternative, take your pick:
function ownList(arr) {
return arr.length ? [[arr.shift()]] . concat(ownList(arr)) : [];
}
Using a bit of ES6 magic for readability:
function ownList([head, ...tail]) {
return head === undefined ? [] : [[head]] . concat(ownList(tail));
}
Here the [head, ...tail] is using parameter destructuring which pulls the argument apart into its first element (head) and an array of remaining ones (tail).
Instead of concat you could also use the array constructor:
function ownList([head, ...tail]) {
return head === undefined ? [] : Array([head], ...ownList(tail));
}
I think your basic assumption is wrong. What you need to do is check if each item in the array is an array, if not just add the item to the new array, if so have the function run itself on the array item.
That is recursion.
This code does that kind of recursion...
function ownList(arr)
{
var newArr = [];
var length = arr.length;
for (var i = 0; i < length; i++) {
if (typeof(arr[i]) === 'object') {
newArr.push(ownList(arr[i]));
continue;
}
newArr.push([arr[i]]);
}
return newArr;
}
var arr = [1, 2, 3];
console.log(ownList(arr));
Would something like this work:
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]],
result = [];
function flatten(input){
input.forEach(function(el){
if(Array.isArray(el)){
flatten(el)
}else{
result.push([el]);
}
});
}
flatten(arr);
console.log(JSON.stringify(result));
//[[1],[2],[3],["a"],["b"],["c"],["str"]]
JSBIN
Edit:
var result = [];
function flatten(input){
if (input.length === 0){
console.log( "result", result ); //[[1],[2],[3],["a"],["b"],["c"],["str"]]
return;
}
//if zeroth el of input !array, push to result
if (!Array.isArray(input[0])){
result.push(input.splice(0, 1));
flatten(input);
}else{
flatten(input[0]); //else, give input[0] back to flatten
}
}
window.onload = function(){
var arr = [1, 2, 3, ["a", "b", "c", ["str"]]];
flatten(arr);
}
JSBIN
After struggling through this today, turns out that this works :)
function ownList(arr){
//base case:
if (arr.length === 1) {
return [arr];
}
//recurse
//have to do two brackets here --> (arr.slice(0,1)) since length > 1
return [arr.slice(0,1)].concat(ownList(arr.slice(1)));
}
var arr = [1,2,3]
console.log(ownList(arr))// returns [[1],[2],[3]]

Categories