Note: Not a duplicate problem.. here I need to skip empty arrays.
Say I have several arrays like:
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
Using following function, I could get the desired result: [4]
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [a, b, c, d].reduce((previous, current) =>
!previous.length || previous.filter((x) => !current.length || current.includes(x)),
);
console.log(res)
I included !current.length || above to bypass empty array c. But this doesn't work if first array in the collection i.e. a is empty. The result would be [].
This code will work as you expected (vanilla JS, support old browsers):
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [a, b, c, d].reduce(function(acc, arr) {
// ignore empty array
if(arr.length == 0) return acc;
// assign first non-empty array to accumudation
if(acc.length == 0) return arr;
// otherwise, accumudation will be insection of current accomudation and current array
return acc.filter(function(n) {
return arr.indexOf(n) !== -1;
});
}, []);
console.log(res)
Just filter. Makes the code much more readable
var a = [1, 2, 3, 4],
b = [2, 4],
c = [],
d = [4];
var res = [c, b, a, d].filter(arr => arr.length).reduce((previous, current) =>
previous.filter((x) => current.includes(x)),
);
console.log(res)
Related
I have two separate arrays and I'm trying to create a new nested array that has values grouped together.
Can I use the map() method and pair each item inside the map method?
There is a similar question here: Map an array of arrays
However, he context is different because I don't have a nested array to begin with.
var letters = [a, b, c];
var numbers = [1, 2, 3];
var lettersAndNumbers = letters.map((letter) => {
numbers.forEach((number) => {
return letter, number;
);
});
// lettersAndNumbers = [[a, 1], [b, 2], [c, 3]]
Thank you for any tips, hints, or solutions!
To do this, use the following
var letters = ['a','b','c'];
var numbers = [1, 2, 3];
var letterAndNumbers = letters.map((letter,index) => {
return [letter,numbers[index]];
})
And if you print it, you will receive the following output
console.log(letterAndNumbers)
[ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
The second parameter of .map() is Index. Make use of it for retrieve a numbers[i] by that iterating index:
const letters = ["a", "b", "c"];
const numbers = [1, 2, 3];
const lettersAndNumbers = letters.map((a, i) => [a, numbers[i]]);
console.log(lettersAndNumbers)
// lettersAndNumbers = [[a, 1], [b, 2], [c, 3]]
I would use a map but here is a reduce just for the sake of it.
var letters = ['a', 'b', 'c'];
var numbers = [1, 2, 3];
var lettersAndNumbers = (letters, numbers) => letters.reduce((results, letter, index) => {
results.push([letter, numbers[index]]);
return results;
}, []);
console.log(lettersAndNumbers(letters, numbers));
This question already has answers here:
Dividing an array by filter function
(14 answers)
Closed 4 years ago.
Is there a way to filter an array of objects to retrieve an array of the values I need but also remove the filtered values from the original list. Something like this
let array = [1, 2, 3, 4, 5];
const filteredList, listContainingRemainingValues = array.filter(value => value > 3);
Output:
filteredList = [4, 5];
listContainingRemainingValues = [1, 2, 3];
Is there any built in functionality to do this already in Javascript or will i have to roll my own?
You could take an array as temporary storage for the wanted result.
const
array = [1, 2, 3, 4, 5],
[remaining, filtered] = array.reduce((r, v) => (r[+(v > 3)].push(v), r), [[], []]);
console.log(filtered);
console.log(remaining);
Same with lodash's _.partition
const
array = [1, 2, 3, 4, 5],
[filtered, remaining] = _.partition(array, v => v > 3);
console.log(filtered);
console.log(remaining);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Here's one option:
const array = [1, 2, 3, 4, 5];
// Get all the indices we want to keep:
const matchingIndices = array
.map((v, i) => [i, v > 3])
.filter((el) => el[1])
.map((el) => el[0]);
// Filter the input array by indices we want/don't want
const matching = array.filter((v, i) => matchingIndices.indexOf(i) >= 0);
const nonMatching = array.filter((v, i) => matchingIndices.indexOf(i) < 0);
Use 2 filters
let array = [1, 2, 3, 4, 5];
let filteredList = array.filter(value => value > 3);
let listContainingRemainingValues = array.filter(f => !filteredList.includes(f))
console.log(filteredList)
console.log(listContainingRemainingValues)
Here's one of the way using underscore library:
var data = [1, 2, 3, 4, 5]
var x = _.reject(data, function(num){ return num > 3; });
var y = _.difference(data, x);
console.log(x);
console.log(y);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
Sort the array, find the index of your threshold value and then splice it in order to remove the elements from the input array and to return the removed elements:
const array = [1, 2, 3, 4, 5];
// just if the input array is not already sorted
array.sort();
const removedElements = removeAndGet(array, 3);
console.log('input array:', array);
console.log('removed elements:', removedElements)
function removeAndGet(input, thresholdValue) {
const ind = input.findIndex(a => a > thresholdValue);
return ind > -1 ? input.splice(ind) : [];
}
This is my array of arrays:
arr_1 = [1,2,3]
arr_2 = [4,5,6]
arr_3 = [7,8,9]
arr = [arr_1, arr_2, arr_3]
arr = [[1,2,3], [4,5,6], [7,8,9]]
What I want to do is push all elements like so that the final array is like the following and insert another element at the beginning of my array:
arr = [[i,1,2], [3,4,5], [6,7,8], [9]]
All sub-arrays must not be more than 3 elements.
Thanks for your help.
You could visit all inner arrays and unshift the leftover values from the previous loop.
var array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
chunk = 3,
item = 'x',
i = 0,
temp = [item];
while (i < array.length) {
array[i].unshift(...temp);
temp = array[i].splice(chunk, array[i].length - chunk);
i++;
}
if (temp.length) {
array.push(temp);
}
console.log(array.map(a => a.join(' ')));
You can use the function reduce
var arr = [[1,2,3], [4,5,6], [7,8,9]],
newElem = "newOne",
all = [newElem, ...arr.reduce((a, c) => [...a, ...c], [])], // All together
// Build the desired output asking for the result of:
// element mod 3 === 0
result = all.reduce((a, c, i) => {
if (i % 3 === 0) a.push([c]);
else a[a.length - 1].push(c);
return a;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could move on each iteration last element from previous array to next one and if the last sub-array has more then 3 elements then remove the last one and add it to new array.
let arr_1 = [1, 2, 3],
arr_2 = [4, 5, 6],
arr_3 = [7, 8, 9],
arr = [arr_1, arr_2, arr_3]
setInterval(function() {
const last = arr.length - 1;
const newElement = parseInt(Math.random() * 30)
arr.forEach((a, i) => {
if(i == 0) a.unshift(newElement);
if(arr[i + 1]) arr[i + 1].unshift(a.pop())
else if(arr[last].length > 3) arr[last + 1] = [arr[last].pop()]
})
console.log(JSON.stringify(arr))
}, 1000)
You can do this quite succinctly with a simple unravel/ravel. It easy to adjust group size too.
let arr = [ [1,2,3], [4,5,6], [7,8,9]]
let newEl = 0
let groupSize = 3
var newArr = [];
var unravelled = arr.reduce((a, c) => a.concat(c), [newEl])
while(unravelled.length) newArr.push(unravelled.splice(0,groupSize));
console.log(newArr)
arr_1 = [1, 2, 3]
arr_2 = [4, 5, 6]
arr_3 = [7, 8, 9]
arr = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
function reassignChunk(x) {
// create an array which will be used to store unwrapped values
var newArray = [];
arr.forEach(function(elem) {
newArray.push(...elem); //using spread operator to unwrap values
});
newArray.unshift(x, limit)
var modArray = [];
var m, j, temparray, chunk = 3;
for (m = 0; m < newArray.length; m = m + limit) {
// creatinging new array using slice
modArray.push(newArray.slice(m, m + limit));
}
console.log(modArray)
}
reassignChunk(13, 3)
arr = [[i,1,2], [3,4,5], [6,7,8], [9]]
Assuming all your elements are numbers, you can do it like this:
Prepend i to the array
Flatten the array
Convert the array to a comma-separated string
Split the string into chunks of at most 3 numeric substrings (2 commas)
Convert the chunks back into arrays of numbers
const arr_1 = [1,2,3];
const arr_2 = [4,5,6];
const arr_3 = [7,8,9];
const i = 42;
const result = [i,...arr_1,...arr_2,...arr_3].join()
.match(/(?:[^,]+(,|$)){1,2}[^,]*/g).map( x => x.split(',').map(Number) )
;
console.log( result );
You may do your 2d unshifting simply as follows;
var arr_1 = [1,2,3],
arr_2 = [4,5,6],
arr_3 = [7,8,9],
arr = [arr_1, arr_2, arr_3],
us2d = (a2d,...is) => is.concat(...a2d)
.reduce((r,e,i) => (i%3 ? r[r.length-1].push(e)
: r.push([e]), r), []);
console.log(JSON.stringify(us2d(arr,0)));
console.log(JSON.stringify(us2d(arr,-2,-1,0)));
I am trying to iterate an array with forEach and, based on a condition, I do something.
For this question, I simplified the condition in order to try to understand what's going on.
I expect array b = [] after the operation, but it is not, as it operates only on half on the elements. Why does this happen?
(This is not about removing everything from b, just trying to understand why it jumps the even indexes).
var a = [1, 2, 3, 4, 5, 6];
var b = a.slice(0);
console.log('before b = ', b); // b = [1, 2, 3, 4, 5, 6]
a.forEach(function (e) {
if (e > 0) {
b.splice(a.indexOf(e), 1);
}
});
console.log('after b = ', b); // b = [2, 4, 6]
// but I expect b = []
It does not. It goes through each and every item. The thing is what you do with array b.
First you remove the index 0 from it which is 1. So now b = [2,3,4,5,6].
Then index 1 which is 3 so b = [2,4,5,6].
Then index 2 which is 5 so b = [2,4,6].
The next indexes don't exist so in the end b = [2,4,6].
To have the expected outcome use b.indexOf(e) in your splice call.
var a = [1, 2, 3, 4, 5, 6];
var b = a.slice(0);
console.log('before b = ', b); // b = [1, 2, 3, 4, 5, 6]
a.forEach(function (e) {
if (e > 0) {
b.splice(b.indexOf(e), 1);
}
});
console.log('after b = ', b); // b = [2, 4, 6]
// but I expect b = []
You could take the index directly for splicing and make an log from the value an the array. You se, that the array becomes smaller than the index for splicing.
var a = [1, 2, 3, 4, 5, 6];
var b = a.slice(0);
console.log(b.join(' '));
a.forEach(function (e, i) {
if (e > 0) {
b.splice(a.indexOf(e), 1);
console.log(i, ': ', b.join(' '));
}
});
console.log(b); // b = [2, 4, 6]
To empty b, you need to look for the index of the array b, not a and splice it.
var a = [1, 2, 3, 4, 5, 6];
var b = a.slice(0);
a.forEach(function (e, i) {
if (e > 0) {
b.splice(b.indexOf(e), 1);
// ^
}
});
console.log(b);
You're splicing based on the index of the element from a, however b's indices are getting updated when you splice in it. You should try to splice from b based on the index of the element IN b.
Is there a javascript keyword to compare two array elements?
For example:
var a = [1,2,3];
var b = [4,2,5];
var c = a.keyword(b) = [0,1,0]
You can use the Array.prototype.map and compare the values to a second array using indexes.
var a = [1,2,3];
var b = [4,2,5];
var c = a.map(function(elem, index){
return elem === b[index];
});
console.log(c);
You could compare the elements at the same index and return 1 or zero, if found or not.
var a = [1, 2, 3],
b = [4, 2, 5];
result = a.map(function (a, i) {
return +(a === b[i]);
});
console.log(result);
ES6
var a = [1, 2, 3],
b = [4, 2, 5];
result = a.map((a, i) => +(a === b[i]));
console.log(result);