I am filtering this list
[
{
appLearningItemId: 67
catalogues: (2) [ {id: 1041, value: "New Catalog"},
{id: 1058, value: "Test"}]
categories: (3) [{id: 1, value: "Soft Skills"},
{id: 3, value: "Non-technical"},
{id: 5, value: "Induction"}]
code: "CCE0013"
suppliers: (3) [{id: 1, value: "Company XYZ Ltd"},
{id: 2, value: "test c2"},
{id: 17, value: "new company"} ]
title: "07 Values & Beliefs"
type: {id: 11377, value: "Elearning"}
}, ... * 682 items
]
with this object and filter
const filters = {
type: 'Elearning',
catalog: 1041,
category: 1,
supplier: 1
}
let advancedFilteredLearningItems = this.originalLearningItems.filter(obj => obj.type.value == filters.type
&& obj.catalogues.some( catalogs => catalogs.id == filters.catalog)
&& obj.categories.some( category => category.id == filters.category)
&& obj.suppliers.some(supplier => supplier.id === filters.supplier));
console.log(advancedFilteredLearningItems)
which works great. Sometimes the filter object will have a null value in some or up to 3 of the values eg:
const filters = {
type: 'Elearning',
catalog: null,
category: 1,
supplier: null
}
how do I edit the filter code to not filter on null items so in this case I get back all E-learning items with a category of 1? Currently the filter code is looking for null values but I just want to omit it from the filter completely.
Would adding a null check to all of your filters work? So if it is null you return true because you want all of the catalogs before it? This isn't the most efficient solution, but it should get you to where you need.
const filters = {
type: 'Elearning',
catalog: 1041,
category: null,
supplier: null
}
let advancedFilteredLearningItems = this.originalLearningItems.filter(obj =>
(filters.type != null ? obj.type.value == filters.type : true)
&& obj.catalogues.some(catalogs => filters.catalog != null ? catalogs.id == filters.catalog : true)
&& obj.categories.some(category => filters.category != null ? category.id == filters.category : true)
&& obj.suppliers.some(supplier => filters.supplier != null ? supplier.id === filters.supplier : true));
console.log(advancedFilteredLearningItems)
EDIT:
A more efficient solution is to not loop through your catalogues if there is no filter. This can be done by adding an extra function
let advancedFilteredLearningItems = this.originalLearningItems.filter(obj =>
(filters.type != null ? obj.type.value == filters.type : true)
&& this.filterItems(filters.catalog, obj.catalogs)
&& this.filterItems(filters.categories, obj.categories)
&& this.filterItems(filters.supplier , obj.suppliers)
console.log(advancedFilteredLearningItems)
// new function
filterItems(filter, array) {
if (filter == null) {
return true;
}
return array.some(item => item.id == filter);
}
EDIT 2: In case you don't want to add a new function, this should be as efficient as my first edit
let advancedFilteredLearningItems = this.originalLearningItems.filter(obj =>
(filters.type == null || obj.type.value == filters.type)
&& (filters.catalog == null || obj.catalogues.some(catalogs => catalogs.id == filters.catalog))
&& (filters.categories == null || obj.categories.some(category => category.id == filters.category))
&& (filters.supplier == null || obj.suppliers.some(supplier => supplier.id == filters.supplier))
);
Related
when we need to compare two objects a and b we also should test that one of them is not null.
However, knowing that is a total chaos
{} - null => -0
[] - null => 0
1 - null => 1
"1" - null => 1
true - null => 1
false - null => 0
"a" - null => NaN
null - null => 0
"a" == null false
"a" > null false
"a" < null false
let arr = [
{ name: "a" },
{ name: null },
null,
{ name: "zaa" },
{ name: "dgh" }
];
let sortByName = function (a, b) {
if (a == null || b == null) return a - b;
if (a.name == null || b.name == null) return a.name - b.name;
return a.name.localeCompare(b.name);
};
console.log(arr.sort(sortByName));
the result is the following:
0: {name: 'a'}
1: {name: null}
2: null
3: {name: 'dgh'}
4: {name: 'zaa'}
how would you explain such a result?
null - {} === NaN
{} - null === -0
Here:
if (a == null || b == null) return a - b;
You are subtracting anything from null or null from anything, if one of the 2 values is null.
Replace null with an empty string and use that in your comparison:
let arr = [
{ name: "a" },
{ name: null },
null,
{ name: "zaa" },
{ name: "dgh" }
];
let sortByName = function (a, b) {
return (a?.name ?? '').localeCompare(b?.name ?? '');
};
console.log(arr.sort(sortByName));
If you want to make it so that null comes before {name: null} you can extend #Cerbrus answer to handle this.
A simple way to do this is convert both terms a and b into values that will in the end sort the way you like. I find the easiest way is to just prefix the input terms with another character you want to sort on.
eg.
If term is null, just return `0`;
If term is `{name:null}` return `1`;
Everything else just return `3` + term;
It's kind of like creating a compound index..
Doing the above you can see it's very easy to make the sort do whatever you want based on certain conditions.. Eg, if you wanted null to go to the end like undefined simply change it's prefix, eg. make it 4
eg.
let arr = [
{ name: "a" },
{ name: null },
null,
{ name: "zaa" },
{ name: "dgh" }
];
function toStr(a) {
if (a === null) return '0';
else if (a.name === null) return '1';
else return '3' + a.name;
}
let sortByName = function (a, b) {
return toStr(a).localeCompare(toStr(b));
};
console.log(arr.sort(sortByName));
The array of objects:
array = [
{
"id": 1,
"key": "key1",
"name": "name1",
"area": "area1",
"functionalArea": "func1",
"lob": "lob1",
},
{
"id": 2,
"key": "key2",
"name": "name2",
"area": "ALL",
"functionalArea": "ALL",
"lob": "ALL",
},
]
My atempt:
const { name, id, functionalArea, area, lob } = this.form.getRawValue();
const searchTerms = {
widgetName,
widgetId,
functionalArea,
area,
lob,
};
.subscribe(
(res) => {
let results = array.filter((item) =>
searchTerms.functionalArea === 'ALL' &&
searchTerms.area === 'ALL' &&
searchTerms.lob === 'ALL' &&
!searchTerms.id &&
!searchTerms.name
? item
: item.key.toLowerCase().includes(searchTerms.widgetId.toLowerCase()) ||
item.name.toLowerCase().includes(searchTerms.widgetName.toLowerCase()) ||
(item.functionalArea.toLowerCase().includes(searchTerms.functionalArea.toLowerCase()) &&
item.area.toLowerCase().includes(searchTerms.area.toLowerCase()) &&
item.lob.toLowerCase().includes(searchTerms.lob.toLowerCase()))
);
},
The problem:
I cannot filter for multiple conditions using includes() function, it does not work.
If i remove all conditions and use only one than the includes() function works.
A filter is a function that return true or false, As always you want to "search" is good at first convert to upperCase (or lowerCase) the "condition"
searchTerms.functionalArea=searchTerms.functionalArea?
searchTerms.functionalArea.toLowerCase():'ALL'
searchTerms.area =searchTerms.functionalArea?
searchTerms.area.toLowerCase():'ALL'
searchTerms.lob =searchTerms.functionalArea?
searchTerms.lob.toLowerCase():'ALL'
searchTerms.name=searchTerms.name?
searchTerms.name.toLowerCase():'ALL'
const result=array.filter((item)=>{ //<--see this bracket
let result=searchTerms.functionalArea=='ALL' ||
searchTerms.functionalArea.includes(item.functionalArea.toLowerCase());
result=result && (searchTerms.area =='ALL' ||
searchTerms.area.includes(item.area .toLowerCase());)
result=result && (searchTerms.lob =='ALL' ||
searchTerms.lob.includes(item.lob .toLowerCase());)
//Update
result=result && (!searchTerms.widgetId ||
searchTerms.widgetId==item.id)
result=result && (!searchTerms.widgetName ||
searchTerms.widgetName.includes(item.name.toLowerCase());)
return result; //<--as you use bracket, you should use return
})
You have to filter only if the conditions about searchTerm are true, something like this:
let results = (searchTerms.functionalArea === 'ALL' &&
searchTerms.area === 'ALL' &&
searchTerms.lob === 'ALL' &&
!searchTerms.id &&
!searchTerms.name)
? array
: array.filter((item) => item.key.toLowerCase().includes(searchTerms.widgetId.toLowerCase()) ||
item.name.toLowerCase().includes(searchTerms.widgetName.toLowerCase()) ||
(item.functionalArea.toLowerCase().includes(searchTerms.functionalArea.toLowerCase()) &&
item.area.toLowerCase().includes(searchTerms.area.toLowerCase()) &&
item.lob.toLowerCase().includes(searchTerms.lob.toLowerCase())));
EXAMPLE (check the console output): https://stackblitz.com/edit/typescript-y2w6sr?file=index.ts
function deptTypes(items) {
return items[Math.floor(Math.random()*items.length)];
}
var items = ["a", "b","c","d","e","f"];
await queryInterface.bulkInsert('reviews', [...Array(50)].map((review) => (
{
user_id: users[Math.floor(Math.random()*users.length)].id,
title: faker.name.title(),
review: faker.lorem.sentences(6),
rating: Math.round(Math.random()*5),
department_type: deptTypes(items),
department_uid: (deptTypes(items) == 'a' ) ? alist[Math.floor(Math.random()*alist.length)].id
:(deptTypes(items) == 'b' ) ? blist[Math.floor(Math.random()*blist.length)].id
: (deptTypes(items)== 'c') ? clist[Math.floor(Math.random()*clist.length)].id
: (deptTypes(items) == 'd') ? dlist[Math.floor(Math.random()*dlist.length)].id
: (deptTypes(items) == 'e') ? elist[Math.floor(Math.random()*elist.length)].id
: flist[Math.floor(Math.random()*flist.length)].id,
created_at: new Date(),
updated_at: new Date()
}
)), {});
what i'm trying is i need the same deptType item that is assigned to department_type and give department_uid a value based on department_type, but im not getting desired result ... please help
At the top of the map function, declare a variable which will be the dept for this iteration:
await queryInterface.bulkInsert('reviews', [...Array(50)].map((review) => {
const dept = deptTypes(items);
return {
user_id: users[Math.floor(Math.random()*users.length)].id,
title: faker.name.title(),
review: faker.lorem.sentences(6),
rating: Math.round(Math.random()*5),
department_type: dept,
department_uid: (dept == 'a' ) ? alist[Math.floor(Math.random()*alist.length)].id
:(dept == 'b' ) ? blist[Math.floor(Math.random()*blist.length)].id
: (dept == 'c') ? clist[Math.floor(Math.random()*clist.length)].id
: (dept == 'd') ? dlist[Math.floor(Math.random()*dlist.length)].id
: (dept == 'e') ? elist[Math.floor(Math.random()*elist.length)].id
: flist[Math.floor(Math.random()*flist.length)].id,
created_at: new Date(),
updated_at: new Date()
};
}), {});
I have the following array:
console.log(array)
[ Data {
sample_id: 'S001',
v_id: 21,
type: 'BD',
sf: 'ETV5',
ef: 'NTRK',
breakpoint1: '8669',
breakpoint2: '1728',
sge: 8,
ege: 19,
som: 207,
wgs: null,
inframe: 1,
platform: 'WR',
rnaconf: 'High',
reportable: 1,
targetable: 1,
path: 'C3',
evidence: null,
summary:
'Same as before',
comments: null },
Data {
sample_id: 'S001',
v_id: 21,
type: 'BD',
sf: 'ETV5',
ef: 'NTRK',
breakpoint1: '8669',
breakpoint2: '1728',
sge: 8,
ege: 19,
som: 207,
wgs: null,
inframe: 1,
platform: 'WR',
rnaconf: 'High',
reportable: 1,
targetable: 1,
path: 'C3',
evidence: null,
summary:
'Same as before',
comments: null },
Data {
sample_id: 'S001',
v_id: 21,
type: 'BD',
sf: 'ETV5',
ef: 'NTRK',
breakpoint1: '8669',
breakpoint2: '1728',
sge: 8,
ege: 19,
som: 207,
wgs: null,
inframe: 1,
platform: 'WR',
rnaconf: 'High',
reportable: 1,
targetable: 1,
path: 'C3',
evidence: null,
summary:
'An interesting development',
comments: null } ]
And the following function:
function diffSummary(o1, o2) {
res = (o1.sample_id === o2.sample_id) && (o1.v_id === o2.v_id) && (o1.type === o2.type) && (o1.sf === o2.sf) && (o1.ef === o2.ef) && (o1.breakpoint1 === o2.breakpoint1) && (o1.breakpoint2 === o2.breakpoint2);
res1 = (o1.sge === o2.sge) && (o1.ege === o2.ege) && (o1.som === o2.som) && (o1.wgs === o2.wgs) && (o1.inframe === o2.inframe) && (o1.platform === o2.platform);
res2 = (o1.rnaconf === o2.rnaconf) && (o1.reportable === o2.reportable) && (o1.targetable === o2.targetable) && (o1.path === o2.path) && (o1.evidence === o2.evidence) && (o1.comments === o2.comments) && (o1.summary !== o2.summary);
if(res && res1 && res2) {
return true;
} else {
return false;
}
}
This above function checks whether two objects in the array are the same, and differ only with respect to their summary value.
I have the following code:
var first = array[0];
var new_array = array.filter(o => (JSON.stringify(o) !== JSON.stringify(first));
var final_array = new_array.filter(o => diffSummary(o, first) === true);
The above code removes all elements in array which are identical to first. It then removes all elements which are identical to first but differ only with respect to the summary value from new_array. I am expecting to get an empty array as a result of these filters.
However, when I print final_array, I get the following:
[ Data {
sample_id: 'S001',
v_id: 21,
type: 'BD',
sf: 'ETV5',
ef: 'NTRK',
breakpoint1: '8669',
breakpoint2: '1728',
sge: 8,
ege: 19,
som: 207,
wgs: null,
inframe: 1,
platform: 'WR',
rnaconf: 'High',
reportable: 1,
targetable: 1,
path: 'C3',
evidence: null,
summary:
'An interesting development',
comments: null } ]
I have tested diffSummary and it does return true when comparing first and the last element of array. I am not sure why the last element of array is not being filtered.
Any insights are appreciated.
It then removes all elements which are identical to first but differ
only with respect to the summary value
This is not what your code is doing, res2 has
(o1.summary !== o2.summary)
which means if they differ then you want to include that object not exclude.
just change that to === and you will get empty output.
Rethink how filter works:
new_array.filter(o => diffSummary(o, first) === true)
// when an object of array will get a `true` value returned from diffSummary function then that element will be collected by filter into resulting array.
// so if res2 alongwith res and res1 is true then only this case will occur
// and your code is checking for o1.summary and o2.summary to be unequal.
// BUT, as per your expectation, you need to remove them when they are unequal. so the `true` condition need to be based on an equality comparison.
Other points (other than comments above)
1- Line
var new_array = array.filter(o => (JSON.stringify(o) !== JSON.stringify(first));
has syntax error, insert one more closing bracket ) at the end
2- Following logic
if (res && res1 && res2) {
return true;
} else {
return false;
}
can be simplified as a one-liner:
return res && res1 && res2;
I am a junior level developer trying to solve a scenario, where i should get an error if we are trying to add an existing object to the array.
Input :
{
id: "0",
name: "sdsd"
}
Existing Arrays:
[{
id: "0",
name: "sdsd"
},
{
id: "1",
name: "sds"
},
{
id: "2",
name: "sdf"
}]
I am expecting the function to be something like
findDuplicate(Array, Object) => return true if there is one, else false.
use the some method, as it will return true / false. If some of the items match true is returned otherwise it will return false if nothing matches (your callback must return a truthy/falsey value).
let items = [
{ id: "0", name: "sdsd" },
{ id: "1", name: "sds" },
{ id: "2", name: "sdf" }
]
// Test "name"
console.log(items.some(i => i.name == 'sdsd'))
console.log(items.some(i => i.name == 'dog'))
// Test "id"
console.log(items.some(i => i.id == '0'))
console.log(items.some(i => i.id == '100'))
// Test both "name" and "id"
console.log(items.some(i => i.name == 'sdsd' && i.id == '0'))
console.log(items.some(i => i.name == 'sdsd' && i.id == '100'))
You can use array filter and array every like follow:
var exist = [{
id: "0",
name: "sdsd"
},
{
id: "1",
name: "sds"
},
{
id: "2",
name: "sdf"
}];
function findDuplicate(array, object){
var result = array.filter(current=>{
return Object.keys(current).every(key =>{
if (object[key] === current[key]){
return key;
}
});
});
//console.log(result);
if (result.length == 0 )
return false;
return true;
}
console.log (findDuplicate(exist,{id:"0",name:"sdsdf"}));
console.log (findDuplicate(exist,{id:"0",name:"sdsd"}));