How filter object values with es6 - javascript

i have a 2 object which i wan't to make filtering with es6
first is my data object and second selected some data.
I wan't to get all items in data object which have second object values
let data = [
{
id: 1,
name: 'A',
status: 1
},
{
id: 2,
name: 'B',
status: 1
},
{
id: 3,
name: 'C',
status: 3
},
{
id: 4,
name: 'D',
status: 2
}
]
and second object is :
let selectedStatus = [
{
id: 1,
status: 1
},
{
status: 3
}
]
in this case i want't to get data object items which contains same statuses in second object so in this case i need to get this result:
data = [
{
id: 1,
name: 'A',
status: 1
},
{
id: 2,
name: 'B',
status: 1
},
{
id: 3,
name: 'C',
status: 3
},
]

You can do like this:
data = data.filter(item =>
selectedStatus.map(s => s.status).includes(item.status)
);

Below snippet will give the expected answer:
var result = [];
data.forEach((value) => {
selectedStatus.forEach(val => {
if(value.status == val.status) {
result.push(value)
}
});
});
console.log(result)

Assuming you do not have any browser restrictions, you can make use of followed by using Array.includes() to check statuses on data which are on selectedStatus, followed by Array.filter() to filter out objects which match the required condition.
const data = [
{
id: 1,
name: 'A',
status: 1
},
{
id: 2,
name: 'B',
status: 1
},
{
id: 3,
name: 'C',
status: 3
},
{
id: 4,
name: 'D',
status: 2
}
]
const selectedStatus = [
{
id: 1,
status: 1
},
{
status: 3
}
];
const res = data.filter(obj => selectedStatus.map(s => s.status).includes(obj.status));
console.log(res);

let result = [];
selectedStatus.forEach(selectedStatus => result = result.concat(data.filter(status => status.status === selectedStatus.status)))

If you want to generate a third list, like your expected result, you can generate a white-list to match against.
const whiteList = selectedStatus.map((sel) => sel.status); // which gives you an array of all selected status you want to filter for
const filteredData = data.filter((data) => ~whiteList.indexOf(data.status)); // please consider that filter returns a new array that contain all items where the condition was falsy. That can be confusing.
to understand the ~ operator please check
https://wsvincent.com/javascript-tilde/
you may struggle with the result of the filtered array. Please consider that array.filter returns a new array that contain all items which did NOT met the condition in other words its a negation. That can be confusing.
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
ES7
const filteredData = data.filter((data) => whiteList.includes(data.status));

Related

JS/ES6/lodash find index of missing elements of two multidimensional arrays

Assuming that I have 2 multidimensional arrays of objects
const products = [
{
id: 1
name: 'lorem'
},
{
id: 3,
name: 'ipsum'
}
];
const tmp_products = [
{
id: 1
name: 'lorem'
},
{
id: 14,
name: 'porros'
},
{
id: 3,
name: 'ipsum'
},
{
id: 105,
name: 'dolor'
},
{
id: 32,
name: 'simet'
}
];
What is the correct way to find the missing indexes by id property?
I'm expecting an output such as [1,3,4] since those objects are not present in products
I found a similar question but applied to plain arrays:
Javascript find index of missing elements of two arrays
var a = ['a', 'b', 'c'],
b = ['b'],
result = [];
_.difference(a, b).forEach(function(t) {result.push(a.indexOf(t))});
console.log(result);
I'd like to use ES6 or lodash to get this as short as possible
You can use sets to do it quickly:
const productIds = new Set(products.map(v => v.id));
const inds = tmp_products
.map((v, i) => [v, i])
.filter(([v, i]) => !productIds.has(v.id))
.map(([v, i]) => i);
inds // [1, 3, 4]
You can use Array.prototype.reduce function to get the list of missing products' index.
Inside reduce callback, you can check if the product is included in products array or not using Array.prototype.some and based on that result, you can decide to add the product index or not.
const products = [
{
id: 1,
name: 'lorem'
},
{
id: 3,
name: 'ipsum'
}
];
const tmp_products = [
{
id: 1,
name: 'lorem'
},
{
id: 14,
name: 'porros'
},
{
id: 3,
name: 'ipsum'
},
{
id: 105,
name: 'dolor'
},
{
id: 32,
name: 'simet'
}
];
const missingIndex = tmp_products.reduce((acc, curV, curI) => {
if (!products.some((item) => item.id === curV.id && item.name === curV.name)) {
acc.push(curI);
}
return acc;
}, []);
console.log(missingIndex);
With lodash you could use differenceWith:
_(tmp_products)
.differenceWith(products, _.isEqual)
.map(prod => tmp_products.indexOf(prod))
.value()
This may not be great for performance, but it depends on how many items you have. With the size of your arrays this should perform ok.

Can we get an object from single object key value in javascript?

I have an array of object - like this -
test: [
{
id:'1',
name:'A'
},
{
id:'2',
name:'B'
},
]
Suppose I have a value 2 that exists in object Test as id. I want to get whole object from array if id value exists in whole array
input - 2,
expected output - {id:'2' , name:'B'}
How Can we get it ? is it any possible solution ?
Simply use find-
const val = [
{
id: '1',
name: 'A',
},
{
id: '2',
name: 'B',
},
];
const res = val.find(obj => obj.id === '2');
console.log(res);
There can be multiple ways to do this. Here is how I did it.
let test = [
{
id: '1',
name: 'A'
},
{
id: '2',
name: 'B'
}
];
let result = (param) => test.filter(el => {
return el.id == param
});
console.log(result(2))

Array of arrays of objects - find object value occurance and return true/false (js)

I have array of array of object as follows:
[
[
{
id: 1,
itemName: 'xxx',
...
},
{
id: 1,
itemName: 'yyy',
...
},
...
],
[
{
id: 2,
itemName: 'aaa',
...
},
{
id: 2,
itemName: 'kkk',
...
},
...
],
[
{
id: 3,
itemName: 'kkk',
...
},
{
id: 3,
itemName: 'yyy',
...
},
...
]
]
I am trying to check if any itemName from objects inside arrays equals given string, but I stuck at the solution that keeps these arrays with such object in one array. Here is my solution:
function isNameAcrossData(givenString){
return arr.map(arrItem =>
arrItem.find(item => item.itemId === givenString)
);
}
My solution doesn't return boolean but just one array with objects, that contain givenString and undefined as last array element. How to modify it to return just true/false value?
Use a .some inside a .some, to see if some of the arrays have at least one element inside matching the condition:
const isNameAcrossData = givenString => arr.some(
subarr => subarr.some(
({ itemName }) => itemName === givenString
)
);
const arr=[[{id:1,itemName:"xxx"},{id:1,itemName:"yyy"}],[{id:2,itemName:"aaa"},{id:2,itemName:"kkk"}],[{id:3,itemName:"kkk"},{id:3,itemName:"yyy"}]];
console.log(isNameAcrossData('xxx'));
console.log(isNameAcrossData('doesntexist'));
You could also flatten the outer array first:
const isNameAcrossData = givenString => arr.flat().some(
({ itemName }) => itemName === givenString
);
const arr=[[{id:1,itemName:"xxx"},{id:1,itemName:"yyy"}],[{id:2,itemName:"aaa"},{id:2,itemName:"kkk"}],[{id:3,itemName:"kkk"},{id:3,itemName:"yyy"}]];
console.log(isNameAcrossData('xxx'));
console.log(isNameAcrossData('doesntexist'));
You could check with some and return an array of boolean with using the wanted property.
function mapHasValue(key, value) {
return data.map(array => array.some(item => item[key] === value));
}
var data = [[{ id: 1, itemName: 'xxx' }, { id: 1, itemName: 'yyy' }], [{ id: 2, itemName: 'aaa' }, { id: 2, itemName: 'kkk' }], [{ id: 3, itemName: 'kkk' }, { id: 3, itemName: 'yyy' }]];
console.log(mapHasValue('id', 3));
Your code returns
[undefined, undefined, undefined]
because map returns an array so this approach won't work
You have first to loop through all the data and check inside then outside the loop assign to some variable true if there is a match.
Basically you have to return after you loop the data.
Working example for both cases:
const arr=[[{id:1,itemName:"xxx"},{id:1,itemName:"yyy"}],[{id:2,itemName:"aaa"},{id:2,itemName:"kkk"}],[{id:3,itemName:"kkk"},{id:3,itemName:"yyy"}]];
function isNameAcrossData(givenString){
let isMatch = false;
arr.map(childArr => {
childArr.map(obj => obj.itemName === givenString ? isMatch = true : null);
});
return isMatch;
}
console.log(isNameAcrossData('kkk'));
console.log(isNameAcrossData('bbb'));

how to calculate a sum of an array in an object

I had a variable like that
const data = {
code: 1,
items: [
{ nickname: 1, name: [
{id : "A"},
{id : "B"}
]
},
{
nickname: 2, name: [
{id: "A"},
{id: "C"}
]
}
]
}
after that, I want to show how many characters: A:2, B:1, C:1
You can do that is following steps:
Use flatMap() on the array data.items
Inside flatMap() use map() to convert all the object to their id and return it from flatMap(). This way you will array ["A","B","A","C"]
Then use reduce() and get an object with count of all the letters.
const data = { code: 1, items: [ { nickname: 1, name: [ {id : "A"}, {id : "B"} ] }, { nickname: 2, name: [ {id: "A"}, {id: "C"} ] } ] }
const res = data.items.flatMap(x =>
x.name.map(a => a.id)
).reduce((ac,a) => (ac[a] = ac[a] + 1 || 1,ac),{});
console.log(res)
const data = {
code: 1,
items: [
{
nickname: 1,
name: [
{ id: "A" },
{ id: "B" }
]
},
{
nickname: 2,
name: [
{ id: "A" },
{ id: "C" }
]
}
]
};
const res = data.items.reduce((acc, next) => {
next.name.forEach(({ id }) => {
acc[id] = acc[id] + 1 || 1;
});
return acc;
}, {});
console.log(res);
You can do that in a single shot using reduce.
Reducing data.items will allow you to add to the accumulator (initially an empty object), the value of the currently looped name property item.
The result will be an object owning all the occurences of each encountered letter in the name property of each array.
Relevant lines explained:
data.items.reduce((acc, next) will call the reduce method on data.items. acc is the reduce accumulator (initially an empty object), next is the currently looped item of data.items.
next.name.forEach(({id}) in this line, we loop the name property of the currently looped item (data.items[n]). ({id}) is a short syntax to acquire the id property of the looped item in the foreach. It's equivalent to (item => item.id).
acc[id] = acc[id] + 1 || 1; tries to increase the property [id] of the accumulator (example: "A" of {}) by 1. If it does not exist, it sets the value to 1.
return acc; returns the accumulator.
You could iterate name and take id in a loop for assigning the count.
const
data = { code: 1, items: [{ nickname: 1, name: [{ id : "A" }, { id : "B" }] }, { nickname: 2, name: [{ id: "A" }, { id: "C" }] }] },
result = data.items.reduce(
(r, { name }) => (name.forEach(({ id }) => r[id] = (r[id] || 0 ) + 1), r),
{}
);
console.log(result);

Compare two Arrays with Objects and create new array with unmatched objects

I have the following two Javascript arrays:
const array1 = [{ id: 1}, { id: 2 }, { id: 3 }, { id: 4}];
const array2 = [{ id: 1}, { id: 3 }];
I now want a new array array3 that contains only the objects that aren't already in array2, so:
const array3 = [{ id: 2}, { id: 4 }];
I have tried the following but it returns all objects, and when I changed the condition to === it returns the objects of array2.
const array3 = array1.filter(entry1 => {
return array2.some(entry2 => entry1.id !== entry2.id);
});
Any idea? ES6 welcome
You could reverse the comparison (equal instead of unqual) and return the negated result of some.
const
array1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
array2 = [{ id: 1 }, { id: 3 }],
array3 = array1.filter(entry1 => !array2.some(entry2 => entry1.id === entry2.id));
// ^ ^^^
console.log(array3);
Nina's answer is a good start but will miss any unique elements in array 2.
This extends her answer to get the unique elements from each array and then combine them:
const
array1 = [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }],
array2 = [{ id: 1 }, { id: 3 }, { id: 5 }],
array3 = array1.filter(entry1 => !array2.some(entry2 => entry1.id === entry2.id)),
array4 = array2.filter(entry1 => !array1.some(entry2 => entry1.id === entry2.id)),
array5 = array3.concat(array4);
console.log(array5);

Categories