This code removes all null values from array:
var array = [ 0, 1, null, 2, "", 3, undefined, 3,,,,,, 4,, 4,, 5,, 6,,,, ];
var filtered = array.filter(function (el) {
return el != null;
});
console.log(filtered);
But when I try this on an array with nested arrays that have null values, the nulls are not removed:
var array = [ [ 1, null, 2 ], [ 3, null, 4 ], [ 5, null, 6 ] ];
var filtered = array.filter(function (el) {
return el != null;
});
console.log(filtered);
The expected output is:
[ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ] ]
Instead of the actual output:
[ [ 1, null, 2 ], [ 3, null, 4 ], [ 5, null, 6 ] ]
How can I change my example to filter null values from the nested arrays?
If your array-of-arrays only has one level, then you can just map it like this:
var filtered = array.map(subarray => subarray.filter(el => el != null));
console.log(filtered);
You need to recursively filter for null, like so:
function removeNull(array) {
return array
.filter(item => item !== null)
.map(item => Array.isArray(item) ? removeNull(item) : item);
}
This function takes an array, and recursively removes all instances of null.
First, I took your solution and wrapped it in a function so that it is able to be called.
Then, after the items are filtered, it's as simple as mapping over the remaining items, checking if each one is an array, and then for each one that is, calling removeNull on it.
EDIT: I had a typo in my code originally, but it should work now.
var arraylist = [0, 1, null, 5];
var i = arraylist.length;
var j =0;
var newlist = [];
while(j < i){
if(arraylist[j] != null){
newlist.push(arraylist[j]);
}
j++;
}
console.log(newlist);
https://jsfiddle.net/L4nmtg75/
var filterFn = function(item) {
if (item instanceof Array) {
// do this if you want to remove empty arrays:
var items = item.splice(0).filter(filterFn);
var length = items.length;
Array.prototype.push.apply(item, items);
return length;
// if you want to keep empty arrays do this:
var items = item.splice(0);
Array.prototype.push.apply(item, items.filter(filterFn))
return true;
}
return item != null;
};
array = array.filter(filterFn);
This will also work on more than 2 level, as it's recursive.
You're examples remove undefined values as well as null values, and your expected output reflects that, so I'm going to assume that you mean you want to recursively remove both undefined and null values. Your example uses a loose equality comparison which means that it will match both null and undefined. While this works, it is much better to be explicit about what you're checking for with strict equality comparison using ===.
You're going to need to use recursion:
Recursion
An act of a function calling itself. Recursion is used to solve problems that contain smaller sub-problems.
- https://developer.mozilla.org/en-US/docs/Glossary/Recursion
This also means that you're going to want to use Array#reduce instead of Array#filter. Use a new array as the accumulator.
Then for each element in the input array where the element is not null or undefined:
if the element is an instance of Array, push the result of calling this function on the element onto the accumulator array,
otherwise push the element onto the accumulator array
Return the accumulator array at the end of the reduce callback as the accumulator
const input = [ [ 1, null, 2 ], null,,,,, [ 3, null, 4 ],,,,, [ 5, null, 6 ],,,,, [ 7, [ 8, undefined, 9 ], 10 ] ]
function recursiveValues(input) {
if(!(input instanceof Array)) return null
return input.reduce((output, element) => {
if(element !== null && element !== undefined) {
if(element instanceof Array) {
output.push(recursiveValues(element))
} else {
output.push(element)
}
}
return output
}, [])
}
const output = recursiveValues(input)
console.log(JSON.stringify(output))
Related
how can i change the values of provided ids ? i keep getting this TypeError: Cannot set properties of undefined (setting 'select')
const data = [
{
id: 1,
select: false
},
{
id: 2,
select: true
},
{
id: 3,
select: true
},
{
id: 4,
select: false
},
{
id: 5,
select: false
}
];
const ids = [1, 2, 4];
let d = [...data];
for (let i = 0; i < d.length - 1; i++) {
const objIndex: number = d?.findIndex((obj: any) => obj.id === ids[i]);
d[objIndex].select = true;
console.log(d);
}
i want to change the boolean values of provided ids and make a new data object (same data but changed boolean values of provided ids) Need Help !
Perhaps instead of searching in the data for specific ID, search in the list of ids, it makes it simpler and depending on size of data and number of ids it might be even faster:
const data = [
{
id: 1,
select: false
},
{
id: 2,
select: true
},
{
id: 3,
select: true
},
{
id: 4,
select: false
},
{
id: 5,
select: false
}
];
const ids = [1, 2, 4];
for (let i = 0; i < data.length; i++) {
if (ids.includes(data[i].id))
data[i].select = true;
}
console.log(data);
You are iterating through d array and you're trying to access ids array with an index that does not point to any value in this array. So .findIndex is returning -1, and when you try to access it in d[objIndex] it is also undefined there because there is no element with that index.
In order to fix your code you would have to iterate first through ids array to get indices of objects with exact ids and then use that index to change the value.
Fixed code:
const data = [
{
id: 1,
select: false
},
{
id: 2,
select: true
},
{
id: 3,
select: true
},
{
id: 4,
select: false
},
{
id: 5,
select: false
}
];
const ids = [1, 2, 4];
let d = [...data];
ids.forEach((id) => {
const objIndex: number = d?.findIndex((obj: any) => obj.id === id);
// safe guard if there is no object with that id
if (objIndex === -1) {
return;
}
d[objIndex].select = true;
})
Your current for loop is doing d.length-1 iterations, so i will go out of the valid index ranges for indexes in ids. As a result, when you try and do ids[i] on a value of i that isn't an index in ids you get back undefined, which ends up with the .findIndex() being unable to find an object as there is no object that has an undefined id property. This causes the next line of code to crash as it tries to update an object in your array that doesn't exist. For your code to work your condition should be i < ids.length;.
However, assuming that data is a state value (which I've gathered here as you've tagged this as reactjs and you've cloned your data array), you shouldn't be modifying your object within data like you currently are. The main problem is that const d = [...data] only does a shallow copy of your array, so your objects are still references, which means you're modifying your state directly when you do d[objIndex].select = true which can cause issues with rerendering.
To resolve that, you could do a deep clone of your array, or instead, use .map() on your data and return a new object if it needs to be updated as shown below. The below uses the spread syntax (...) to create a new object with all the properties of the current object if its id is in ids, and then we overwrite the value of select to update it to true:
const data = [{ id: 1, select: false }, { id: 2, select: false }, { id: 3, select: false }, { id: 4, select: false }, { id: 5, select: false } ];
const ids = [1, 2, 4];
let newData = data.map(obj => ids.includes(obj.id) ? {...obj, select: true} : obj);
console.log(newData);
[
{
"stockId":2,"vendorId":1,"vendorCode":"Aya - 01","price":2100
},
null,
null
]
remove the null array from arraylist
arr = [ { "stockId":2,"vendorId":1,"vendorCode":"Aya - 01","price":2100 }, null, null ]
arr = arr.filter(elem => elem != null)
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
For example, if you want to remove null or undefined values:
var array = [ { "stockId":2,"vendorId":1,"vendorCode":"Aya - 01","price":2100 }, null, null ];
var filtered = array.filter(function (el) {
return el != null;
});
console.log(filtered);
If you want to remove false values, do something like this
var array = [
{ stockId: 2, vendo`enter code here`rId: 1, vendorCode: 'Aya - 01', price: 2100 },
null,
null,
];
newArray = array.filter(item => !!item);
More simple and concise solution:
let newArray = array.filter(Boolean);
just pass javascript Boolean (builtin) function inside filter as callback function.
I don't know why when I change a variable that's a copy of an another var , both are changed? that doesn't make any sense for me ?
Can you please explain me why ? it's my first time that I face this reaction in node js , I know this in C or C++ when using Pointers but in node js I don't know why !
function getByType(where) {
var object = {
topMarque: null,
posModel: null,
};
var countPer = "titre";
var copywhere = where;
if (where.categorie == "voiture") {
countPer = "marqueNom";
copywhere.marqueId = {
[Op.ne]: null
}
} else {
console.log("------------------------------------------");
console.log(where)
console.log("------------------------------------------");
copywhere.titre = (where.titre) ? where.titre : {
[Op.ne]: null
}
console.log("******************************************");
console.log(where)
console.log("******************************************");
}
return db.stats.findAll({
attributes: [countPer, [db.sequelize.fn('COUNT', db.sequelize.col(countPer)), 'total']],
group: [countPer],
limit: 5,
where: copywhere,
order: [
[db.sequelize.fn('COUNT', db.sequelize.col(countPer)), 'DESC'],
],
}).then(function(count) {
object.topMarque = count;
return db.stats.findAll({
attributes: ['pos', [db.sequelize.fn('COUNT', db.sequelize.col('pos')), 'total']],
group: ['pos'],
where: where
}).then(function(countPosCu) {
object.posModel = countPosCu;
return Promise.resolve(object);
});
}).catch(error => {
return Promise.resolve(object);
})
}
In the first log i have this :
------------------------------------------
{ categorie: 'moto' }
------------------------------------------
In the seconde log I have this :
******************************************
{ categorie: 'moto', titre: { [Symbol(ne)]: null } }
******************************************
If you are dealing with the object or array in javascript it will referring the same reference no matter whether you are copy array/Object in another variable it will change value for all variable belong from the same reference
Please check below example:
// Declaring Array
var arr1 = [1,2,3,4,6];
//Trying to copy array into another variable
var arr2 = arr1;
console.log("========================");
//Display Array one
console.log(arr1);
//Adding more value in arra1
arr1.push(10);
arr1.push(11);
console.log("========================");
////Display Array Two
console.log(arr2);
console.log("========================");
O/P :
========================
[ 1, 2, 3, 4, 6 ]
========================
[ 1, 2, 3, 4, 6, 10, 11 ]
========================
As you can see in above example we are declaring one array and copy that same array into another array then we have push two array inside arr1 and we display arry2 it will display array value which is referring to arr1
This question already has answers here:
Filter Array of Array for values inside nested array
(4 answers)
Only specific 'columns' from a 2d javascript array
(4 answers)
Closed 4 months ago.
I have these variables:
var arr = [
[ "name1", 2, "filter1" ],
[ "name2", 5, "filter2" ],
[ "name3", 8, "filter3" ],
[ "name4", 1, "filter2" ]
];
// This variable may have values: `"filter1"`, `"filter2"`, `"filter3"`.
var filter = "filter2";
How can I filter the array arr according to the filter variable values?
My example must return this:
[
[ "name2", 5 ],
[ "name4", 1 ]
]
Beside the filtering, you need to get only the first two elements of the inner arrays.
Array#filter returns the same elements in the array. For getting the wanted items without the filter item, you need to return either the first two objects, or filter the items with the given filter as well (proposal 2).
var array = [['name1', 2, 'filter1'], ['name2', 5, 'filter2'], ['name3', 8, 'filter3'], ['name4', 1, 'filter2']],
filter = 'filter2',
result = array.filter(a => a[2] === filter).map(a => a.slice(0, 2));
console.log(result);
var array = [['name1', 2, 'filter1'], ['name2', 5, 'filter2'], ['name3', 8, 'filter3'], ['name4', 1, 'filter2']],
filter = 'filter2',
result = array
.filter(a => a.some(v => v === filter))
.map(a => a.filter(v => v !== filter));
console.log(result);
By using filter method you can easily test what you want and only return the match elements
var arr = [['name1', 2, 'filter1'], ['name2', 5, 'filter2'],['name3', 8, 'filter3'], ['name4', 1, 'filter2']];
var filter = 'filter2';
var result = arr.filter(function(res){
return res[2] == filter;
}).map(function(filtered){
return filtered.slice(0,2);
});
console.log(result);
What would be the most elegant solution to find all unique first level entries inside a multidimensional javascript array? There is only one important rule: the order of the entries is important only on the first level, but not important on the second level
For example, for the following array the script should return 4 unique entries (the first, the third, the fourth and the fifth):
[
[ [],[22],[1,13,17],[12],[] ],
[ [],[22],[17,13,1],[12],[] ],
[ [],[12],[1,13,17],[22],[] ],
[ [11],[12],[13],[14],[15] ],
[ [15],[14],[13],[12],[11] ]
]
PS. jQuery can be used as well.
First of all, here is a working JSFiddle for you to play around with: http://jsfiddle.net/missyalyssi/ro8o94nk/
Given an input array the function findUnique will return an array containing items that are unique according to your definition. So, for example:
[[8],[1,2,3],[9]] is a duplicate of [[8], [3,1,2], [9]] but it is not a duplicate of [[9], [3,1,2], [8]]
My main focus when writing this was to make it easy to read and understand.
function findUnique(input) {
let found = [];
let uniqueEls = new Set();
let hasDup = true;
for (let element of input) {
hasDup = found.length &&
found.every((el) => {return deepEqualsNaive(el, element)});
if (hasDup) {
uniqueEls.delete(element);
continue;
}
found.push(element);
uniqueEls.add(element);
}
return [...uniqueEls];
}
This function uses deepEqualsNaive to determine if two arrays are equal. Since object equality in javascript means that the arrays would point to the same memory location we need to build our own function to return true for what we are calling equal. Here, by equal we mean that they have the same elements even though they are not pointing to the same memory location, or appearing in the same order.
I have written this function recursively for readability I do not know the context that you are using this in. If you could overflow the stack then use an iterative version.
Here are some example inputs and what we would expect:
deepEqualsNaive([ [],[22],[1,13,17],[12],[] ], [ [],[22],[17,13,1],[12],[] ]) => true
deepEqualsNaive([ [],[22],[17,13,1],[12],[] ], [ [],[12],[1,13,17],[22],[] ]) => false
deepEqualsNaive([ [],[22],[1,13,17],[12],[] ], [ [],22,[17,13,1],[12],[] ]) => false
The function:
function deepEqualsNaive (input, clone) {
if (!Array.isArray(input) || !Array.isArray(clone)) return false;
if (input.length !== clone.length) return false;
var result = 0;
for (let elIdx = 0; elIdx < input.length; elIdx++) {
var tryDeep = true;
if (Array.isArray(input[elIdx])) tryDeep = deepEqualsNaive(input[elIdx], clone[elIdx]);
if (!tryDeep) return false;
result ^= input[elIdx];
result ^= clone[elIdx];
}
return result === 0;
}
If you're not all that worried about performance and just need something that works, you could use the constant depth you mentioned along with the string representation as a "fingerprint" of sorts (akin to Java's hashcode).
Then you use a Set to keep track of items you've not seen before, and add only those that are new.
function getUnique(rows) {
let unique = new Set();
let results = [];
for (let row of rows) {
// Fingerprint is the string representation of the row,
// with the inner-level sorted (as order doesn't matter).
// E.g., fingerprint of [ [8], [3, 2, 1], [9] ] is '[[8],[1,2,3],[9]]'
let fingerprint = JSON.stringify(row.map((cells) => {
return cells.concat().sort(); // Use concat to avoid sorting in place.
}));
// If we haven't seen this fingerprint before,
// add to the filter and the results list.
if (!unique.has(fingerprint)) {
unique.add(fingerprint);
results.push(row);
}
}
return results;
}
This, for example, will come up with...
> x = [
... [ [8], [3, 2, 1], [9] ],
... [ [7], [8, 3, 9], [1, 2] ],
... [ [8], [1, 2, 3], [9] ],
... ];
> getUnique(x);
[ [ [ 8 ], [ 3, 2, 1 ], [ 9 ] ],
[ [ 7 ], [ 8, 3, 9 ], [ 1, 2 ] ] ]
Obviously if your inner values are non-primitives (objects, arrays, etc) then this will fall over, but if you're dealing with numbers like your example, it should be fine.
If it's ok to have reference to the original array 'records' and inner arrays (that is, no deep copy), you can use something like:
function distinct(arr){
const res =[], //array with results
cmpArr = (a1,a2) => a1.length===a2.length && a1.every((i,ind) => a2[ind] === i),
cmpRec = (a1,a2) => [1,2,3].every(i=> cmpArr(a1[i],a2[i])); //compare 'records' for indices 1,2 and 3
for(let subarr of arr){
subarr[2].sort(); //NB, this alters the source array. If this is not allowed, a work around can be created
if(!res.some(r => cmpRec(r,subarr))) //check if 'res' doesn't have an entry , based on the cmpRec function
res.push(subarr);
}
return res;
}
//test:
let input = [
[ [],[22],[1,13,17],[12],[] ],
[ [],[22],[17,13,1],[12],[] ],
[ [],[12],[1,13,17],[22],[] ],
[ [11],[12],[13],[14],[15] ],
[ [15],[14],[13],[12],[11] ]
];
console.log(distinct(input).map(JSON.stringify));