Filter deep nested array - javascript

I'm having some issues with filtering 2 arrays of objects. My goal is to filter the main array with another array, both arrays of numbers.
Demo code below
partners?.map((e) => {
let products = e.products.map(a => a.externalProductId)
let porArr: number[] = active.map((a) => a.externalProductId);
if (products.filter(item => porArr.includes(item))) {
return console.log(e)
} else {
return console.log('bad')
}
})
products preview
[
6268,
6267,
9745,
9746
]
porArr preview
[
6267,
6270,
6269,
6641,
9559,
9560,
9660,
9663,
9665
]
for some reason the func still returns always true in the if rule.
Any help greatly welcome!

Since you're not assigning the filtered array anywhere, you don't need to use .filter(). Use .some() to test if any of the array elements satisfy the condition.
if (products.any(product => porArr.includes(product)) {
// do something
}

Related

Simplifying an Array containing an array of objects

I have this array of customer licenses I am sorting through and creating a live search function with an array that updates properly. The issue I am facing is that I want my filtered array to be an array like this [[{},{},{},{},{}]] currently after typing in a word to filter the array looks like this instead [ [{}], [{},{}], [{},{}] ] or something similar whereas its an array with multiple arrays instead of just one.
I'm sure its something simple that I have overlooked in the past couple of hours trying to figure out how to achieve what I want.
function FilterResults(term, results)
{
return results.reduce((filtered, group) =>
{
const match = group.filter(({ customerName }) => customerName.toLowerCase().includes(term.toLowerCase()));
match.length && filtered.push(match);
return filtered;
}, []);
}
I am not sure if you really want an array inside of another array but
You can do it like this one.
I have spread and then pushed the match array and returned the result in a new array.
function FilterResults(term, results)
{
const res = results.reduce((filtered, group) =>
{
const match = group.filter(({ customerName }) => customerName.toLowerCase().includes(term.toLowerCase()));
match.length && filtered.push(...match);
return filtered;
}, []);
return [res]
}

How do I search array within an object for any instances of specified string values?

How do I search an array for any instances of multiple specified string values?
const arrayOfObjects = [{
name: box1,
storage: ['car', 'goat', 'tea']
},
{
name: box2,
storage: ['camel', 'fox', 'tea']
}
];
arrayOfSearchItems = ['goat', 'car', 'oranges'];
If any one or all of the arrayOfSearchItems is present in one of the objects in my array, I want it to either return false or some other way that I can use to excluded that object that is in my arrayOfObjects from a new, filtered arrayOfObjects without any objects that contained the arrayOfSearchItems string values. In this case I would want an array of objects without box1.
Here is what I have tried to do, based on other suggestions. I spent a long time on this. The problem with this function is that it only works on the first arrayOfSearchItems strings, to exclude that object. It will ignore the second or third strings, and not exclude the object, even if it contains those strings. For example, it will exclude an object with 'goat'. Once that happens though, it will no longer exclude based on 'car'. I have tried to adapt my longer code for the purposes of this question, I may have some typos.
const excludeItems = (arrayOfSearchItems, arrayOfObjects) => {
let incrementArray = [];
let userEffects = arrayOfSearchItems;
let objects = arrayOfObjects;
for (i = 0; i < userEffects.length; i++) {
for (x = 0; x < objects.length; x++) {
if (objects[x].storage.indexOf(userEffects) <= -1) {
incrementArray.push(objects[x]);
}
}
}
return(incrementArray);
}
let filteredArray = excludeItems(arrayOfSearchItems, arrayOfObjects);
console.log(filteredArray);
Thanks for providing some example code. That helps.
Let's start with your function, which has a good signature:
const excludeItems = (arrayOfSearchItems, arrayOfObjects) => { ... }
If we describe what this function should do, we would say "it returns a new array of objects which do not contain any of the search items." This gives us a clue about how we should write our code.
Since we will be returning a filtered array of objects, we can start by using the filter method:
return arrayOfObjects.filter(obj => ...)
For each object, we want to make sure that its storage does not contain any of the search items. Another way to word this is "every item in the starage array does NOT appear in the list of search items". Now let's write that code using the every method:
.filter(obj => {
// ensure "every" storage item matches a condition
return obj.storage.every(storageItem => {
// the "condition" is that it is NOT in the array search items
return arrayOfSearchItems.includes(storageItem) === false);
});
});
Putting it all together:
const excludeItems = (arrayOfSearchItems, arrayOfObjects) => {
return arrayOfObjects.filter(obj => {
return obj.storage.every(storageItem => {
return arrayOfSearchItems.includes(storageItem) === false;
});
});
}
Here's a fiddle: https://jsfiddle.net/3p95xzwe/
You can achieve your goal by using some of the built-in Array prototype functions, like filter, some and includes.
const excludeItems = (search, objs) =>
objs.filter(({storage:o}) => !search.some(s => o.includes(s)));
In other words: Filter my array objs, on the property storage to keep only those that they dont include any of the strings in search.

Filtering an object array with another array

I am having a filtering problem..
objArray is the array that needs to be filtered.
selectedNames is an array that contains the values that I want to find in objArray.
I need to fetch all objects that have one or more values from selectedNames in their "names" property (an array) .
The output I am trying to get is :
let result = [{names:["A","B","C","D"]},
{names:["A","B"]},
{names:["A","D"]}
]
Here is a simplified version of my code:
let objArray = [{names:["A","B","C","D"]},
{names:["C","D"]},
{names:["C","D","E"]},
{names:["A","B"]},
{names:["A","D"]}
]
let selectedNames = ["A","B"]
result = this.objArray .filter(obj => {
return this.selectedNames.includes(obj.names)
}
My code seems to work fine if names attribute was a single value and not an array. But I can't figure out how to make it work on an array.
Any help is more than welcome
You could do something like this. Filtering the array based on the names property having 'some' value be included in the selectedNames array.
...
objArray.filter(obj => obj.names.some(name => selectedNames.includes(name)));
[Edit] As #RadicalTurnip pointed out, this is not performant if the selectedNames is too large. I would suggest that you use an object. E.x
...
const selectedNamesMap = selectedNames.reduce((p,c) => ({...p, [c]: true}), {});
objArray.filter(obj => obj.names.some(name => selelectedNamesMap[name]));
Overkill, but if the arrays are really large (millions of elements) then you are better of using regular for loop and not array methods.
This result is not performant scaled up, but I don't know that there is any way to ensure that it will be performant unless you know more information (like the names are already sorted). That being said, you just missed one more piece of logic.
result = this.objArray.filter(obj => {
let toReturn = false;
obj.names.forEach(name => {
if (this.selectedNames.includes(name))
toReturn = true;
};
};
return toReturn;
};

JavaScript chaining promises to return an array of all data returned from all promises [duplicate]

This question already has answers here:
Merge/flatten an array of arrays
(84 answers)
Closed 2 years ago.
I have a scenario where I need to call a "getData" method. This "getData" method will call the server to get items, then for each item i need to get the child items. The "getData" method should return a single array of ALL of the child items in a single array.
For example, i have
item1
childA, childB, childC
item2
childD
item3
childE, childF
I would like to get a single array containing
[childA, childB, childC, childD, childE, childF]
I have tried the following code but this is not quite right.
export function getData() {
return getItems()
.then((items) =>{
var promises = [];
items.forEach((item) => {
promises.push(
return getChildItems({
item: `${item}`,
})
.then((childItems) => {
return childItems
}),
);
});
return Promise.all(promises)
.then((allChildItems) => allChildItems);
});
}
This returns an array where each element is an array. The top level array's number of elements is the number of items. Each child array contains the number of elements matching the number of child items for that item. For example,
[
[childA, childB, childC],
[childD],
[childE, childF]
]
How can i get it to return a single array like
[childA, childB, childC, childD, childE, childF]
UPDATE:
I found a solution, but I do not this its particularly elegant. In the PromiseAll, i loop over the top level items and them concat the child arrays into a single array and return it,
return Promise.all(promises)
.then((arrayOfChildItemsArrays) => {
let allChildItems = []
arrayOfChildItemsArrays.map((childItemsArray) => {
allChildItems = allChildItems.concat(childItemsArray);
});
return allChildItems;
});
Surely there is a nicer way to do this?
You can flatten the array via Array.prototype.flat:
return Promise.all(promises).then(allChildItems => allChildItems.flat());
One solution is to keep your current code and call flat(Infinity) on the result. That'll give you a flattened array. Here's a slightly shortened version of that:
export function getData() {
return getItems()
.then((items) => Promise.all(items.map(item => getChildItems({item: `${item}`))))
.then((childArrays) => {
return childArrays.flat(Infinity);
});
}
I've used Infinity there, but the default is 1 and that would probably be good enough for your use case.
Alternatively, you can loop through them yourself (flat is relatively new, but it's also easily polyfilled):
export function getData() {
return getItems()
.then((items) => Promise.all(items.map(item => getChildItems({item: `${item}`))))
.then((childArrays) => {
const result = [];
for (const array of childArrays) {
result.push(...array);
}
return result;
});
}

lodash filter array of objects by array Angular 5

Say I have an object like so...
and I have an array with ids like this..
array = ['21d32fwef23fw32f3', '21we3weasdf23rfwfwf3']
how can I return only the objects that have sys.ids that match the ids in the array
Ive tried using lodash like so..
getWeekItems(weekNumber) {
this.contenfulService.getWeekItems(weekNumber)
.then((weekOverview) => {
this.weekOverviewCompleted = _.filter(weekOverview, this.completedIds);
console.log(this.weekOverviewCompleted);
}).then(() => console.log(this.weekOverview));
}
but Im getting an empty array back??
is there a better way to do this??
This is how you can get the filtered result :
_.filter(weekOverview, (item) => {
return this.completedIds.indexOf(item.sys.id) > -1 ;
});
// OR Simple javascript filter function
weekOverview.filter(item => {
return this.completedIds.indexOf(item.sys.id) > -1 ;
})
JS function 'filter' does not work on mobile devices. Use the same function defined in Lodash library.

Categories