I am creating a custom search and I have an array of objects.
const data = [{
name: "Janet McKenly",
age: 49,
city: "Baltimore",
active: "2019-02-15",
role: "Admin. Assistant"
},
{
name: "Eric Brown",
age: 23,
city: "Dallas",
active: "2020-06-01",
role: "Janitor"
},
{
name: "Nora Payne",
age: 41,
city: "Los Angeles",
active: "2020-10-02",
role: "Sales Associate"
}
]
I have another array that is dynamically created that allows only for the specific parameters to search in.
let searchColumnOnlyArray = ["name", "city", "active"]; // (generated dynamically)
role & age should not be searchable.
The goal is to only search values for keys set in searchColumnOnlyArray.
I am able to filter by hardcoding a name parameter ["name"] but the searchColumnOnlyArray is dynamic and will change... below is the method I am using:
searchTable(term: any, data: any) {
let search = data.filter((indivitem: object) => {
if(indivitem["name"] === term) {
return indivitem;
}
}
console.log("searchResults", search);
}
I need advice on how to use my searchColumnOnlyArray to only search values in those keys. Advice on how I can constrain my filter to look/search values using the set keys in searchColumnOnlyArray?
You can use the .some() method for each individual item within your filter callback. With the .some() method, you can iterate through your columns array and return true when one of the given column values (ie: keys) holds a value which matches your search term. If your .some() callback never returns true, and false for every column item/key, then the result of calling .some() will be false, which will result in the filter method not keeping the item in the final resulting array:
const data = [ { name: "Janet McKenly", age: 49, city: "Baltimore", active: "2019-02-15", role: "Admin. Assistant" }, { name: "Eric Brown", age: 23, city: "Dallas", active: "2020-06-01", role: "Janitor" }, { name: "Nora Payne", age: 41, city: "Los Angeles", active: "2020-10-02", role: "Sales Associate" } ];
const searchColumnOnlyArray = ["name", "city", "active"];
const term = "Dallas";
const search = data.filter(item =>
searchColumnOnlyArray.some(col => item[col] === term)
);
console.log("searchResults", search);
Note: In your example, you are returning the item which you want to keep in the filter method, while this works, it's not how you should be using .filter(). Your callback should be returning true/false (or a truthy/falsy value). When you return true, the current item is kept in the resulting array returned by .filter(), if you return false then it is not kept in the resulting arrray.
data.forEach(ele => {
searchColumnOnlyArray.forEach( search => {
console.log(ele[search]);
});
});
I can't try the code right now but this should do the job
Related
I've been looking at a problem for hours and failing to find a solution. I'm given an array of customer objects.
In each customer object is an array of friends.
In the array of friends is an object for each friend, containing some data, including a name key/value pair.
What I'm trying to solve for: I'm given this customers array and a customer's name. I need to create a function to find if this customer name is in any other customer's friend lists, and if so, return an array of those customer's names.
Below is a customer list. And as an example, one of the customers is Olga Newton. What the code should be doing is seeing that Olga Newton is a customer and is also in the friends lists of Regina and Jay, and should be returning an array of Regina and Jay.
I thought I could do this simply with a filter function, but because the friends list is an array with more objects, this is adding level of complexity for me I can't figure out.
Below is a customer array. The out put should be
['Regina', 'Jay']
and what I've gotten has either been
[{fullCustomerObj1}, {fullCustomerObj2}]
or
[ ]
What am I missing?
Here is the customer array:
var customers = [{
name: "Olga Newton",
age: 43,
balance: "$3,400",
friends: [{
id: 0,
name: "Justice Lara"
}, {
id: 1,
name: "Duke Patrick"
}, {
id: 2,
name: "Herring Hull"
}, {
id: 3,
name: "Johnnie Berg"
}]
}, {
name: "Regina",
age: 53,
balance: "$4,000",
friends: [{
id: 0,
name: "Cheryl Kent"
}, {
id: 1,
name: "Cynthia Wells"
}, {
id: 2,
name: "Gutierrez Waters"
}, {
id: 3,
name: "Olga Newton"
}]
}, {
name: "Jay",
age: 28,
balance: "$3,000",
friends: [{
id: 0,
name: "Cross Barnett"
}, {
id: 1,
name: "Raquel Haney"
}, {
id: 2,
name: "Olga Newton"
}, {
id: 3,
name: "Shelly Walton"
}]
}];
Use filter and map, please.
function friends(c, name){
return c.filter((a) => {
return a.friends.map(b => b.name).includes(name)
}).map(a => a.name);
}
console.log(friends(customers, "Olga Newton"));
// ['Regina', 'Jay']
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
We look to an array (friends[]) inside anther (customers[]), So used two for loops, the first determine witch customer will look for his friends, and the second the array will search inside, then set if statement if the cust name is inside friends[]: adding the customer name to customerFriends[] array, At the end return the customerFriends[].
let cust = "Olga Newton"; // Get the customer name who you look for his friends.
const findFriend = (cust, arrs) => { // Create findFriend function.
let customerFriends = []; // Create an array to set the result to it.
for (let i = 0; i < arrs.length; i++) { // For each Customer.
for (const arr of arrs[i].friends) { // For each Friend.
if (arr.name === cust) { // Use Strict equality to find Customer name in friends[].
customerFriends.push(arrs[i].name); // Add the customer name to the customerFriends[].
}
}
}
return customerFriends;// Return the final results.
}
console.log(findFriend(cust, customers)); // Call the function.
I have a object which has some properties for one user, and I have array of objects which is returned from API.
My goal is to check which object of Array of objects has the same property as the one single initial object, and then it should return only part of it's properities.
I have tried to use .map on Array of objects but it seems not workig.
Below is the code example. I have also prepared codesandbox if You wish.
const user =
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
car: "audi"
}
;
const usersAnimal = [
{
name: "jan",
lastName: "kowalski",
fullName: "jan kowalski",
animal: "cat",
animalSize: "small",
animalName: "Bat"
},
{
name: "john",
lastName: "smith",
fullName: "john smith",
animal: "dog",
animalSize: "middle",
animalName: "Jerry"
},
{
name: "Anna",
lastName: "Nilsson",
fullName: "Anna Nilsson",
animal: "cow",
animalSize: "big",
animalName: "Dorrie"
}
];
const filtered = usersAnimal.map((userAnimal)=>userAnimal.fullName === user.fullName && return userAnimal.animalName & userAnimal.animalSize & userAnimal.animal);
thanks
https://codesandbox.io/s/admiring-edison-qxff42?file=/src/App.js
For case like this, it would be far easier if you filter it out first then proceed using map:
const filtered = usersAnimal
.filter((animal) => animal.fullName === user.fullName)
.map(({ animalName, animalSize, animal }) => {
return {
animalName,
animalSize,
animal
};
});
I am providing a for loop solution as I haven't learnt many array methods in javascript.
For me the simplest option is to use a for loop and an if check to loop through the arrays values to check for included values.
for (let v in usersAnimal) {
if (usersAnimal[v].fullName === user.fullName) {
console.log(usersAnimal[v])
}
}
The code above will log the entire usersAnimal object containing the fullname we are looking for.
{
name: 'jan',
lastName: 'kowalski',
fullName: 'jan kowalski',
animal: 'cat',
animalSize: 'small',
animalName: 'Bat'
}
commented for further understanding
for (let v in usersAnimal) {
//loops though the array
if (usersAnimal[v].fullName === user.fullName) {
//when the index value 'v' has a fullname that matches the user fullname value
// it passes the if check and logs that object value
return console.log(usersAnimal[v])
//return true...
}
//return null
}
//etc
If you want to filter, I recommend you to use filter.
The map method will create a new array, the content of which is the set of results returned by each element of the original array after the callback function is operated
const user = {name:"jan",lastName:"kowalski",fullName:"jan kowalski",car:"audi"};
const usersAnimal = [{name:"jan",lastName:"kowalski",fullName:"jan kowalski",animal:"cat",animalSize:"small",animalName:"Bat"},{name:"john",lastName:"smith",fullName:"john smith",animal:"dog",animalSize:"middle",animalName:"Jerry"}];
// Get an array of matching objects
let filtered =
usersAnimal.filter(o => o.fullName === user.fullName);
// You get the filtered array, then you can get the required properties
filtered.forEach(o => {
console.log(
'animal:%s, animalSize:%s, animalName:%s',
o?.animal, o?.animalSize, o?.animalName
);
});
// Then use map to process each element
filtered = filtered.map(o => {
const {animal, animalSize, animalName} = o;
return {animal, animalSize, animalName};
});
console.log('filtered', filtered);
thanks for taking a look at this. Sorry for length, trying to be clear!
WHAT I'M TRYING TO DO:
I have an array of users (each user an object) and am trying to filter the users on multiple criteria ("males from France" OR "females from Spain and United States with Engineering skills" etc) but it's proven beyond my skills so far.
The hard part has been that the users are objects within a User array, but within each user object, some values are additional objects or arrays. Here's what the user data array looks like (abbreviated):
let users = [
{
gender: 'male',
location: {street: 'Clement Street', country: 'United States'},
skills: ['engineering', 'underwater'],
}, ...
Notice gender is just a normal property/value but country is within a location object and skills are within an array.
I already have a search button interface that creates toggle buttons to search on each criteria available, and every time you click a button, I add or remove that criteria in a filter object. The filter object looks like this, and uses arrays inside it so that I can define multiple criteria at once, like multiple countries to search, multiple skills, etc.:
filter: {
gender: ['female'],
location: {
country: ['Spain'],},
skills: ['optics', ]
},
WHERE I REALLY GET STUCK
I've created a filterData method that can successfully filter based on Gender (male or female) but can't get it to ALSO filter on country (within the location object) or skills (within the skills array). My current filterData method only goes through one iteration per user, but I've tried For loops and forEach to try to go through each of the filter's criteria ('Spain', 'Optics'), but it just doesn't work. I only get gender.
I think I have two problems: 1) somehow conveying in the code that the item 'key' in some cases will not be a value, but an object or array that must also be searched within, and 2) creating some kind of looping behavior that will go through each of the filter criteria, instead of stopping after the first one (gender).
That's apparently over my head right now, so any guidance or suggestions would be appreciated, thanks very much! And here's all the code I've been working with, including my filterData method.
var filtering = {
filter: {
gender: ["female"],
location: {
country: ["Spain"],
},
skills: ["optics"],
},
users: [
{
gender: "male",
name: "John",
location: { street: "Clement Street", country: "United States" },
skills: ["engineering", "underwater"],
},
{
gender: "female",
name: "Mary",
location: { street: "5th Avenue", country: "Spain" },
skills: ["confidence", "optics"],
},
{
gender: "male",
name: "David",
location: { street: "Vermont Ave", country: "France" },
skills: ["cards", "metalurgy", "confidence"],
},
{
gender: "female",
name: "Rachel",
location: { street: "Vermont Ave", country: "France" },
skills: ["disguise", "electrical"],
},
{
gender: "female",
name: "Muriel",
location: { street: "Vermont Ave", country: "Germany" },
skills: ["flight", "surveillance"],
},
],
filterData: (filter) => {
const filteredData = filtering.users.filter((item) => {
for (let key in filter) {
if (!filter[key].includes(item[key])) {
return false;
}
return true;
}
});
console.log(filteredData);
},
};
filtering.filterData(filtering.filter);
There's a nifty trick called recursion, which is a function calling itself.
The updated code are: checkUserand
filterData
var filtering = {
filter: {
gender: ["female"],
location: {
country: ["Spain"],
},
skills: ["optics"],
},
users: [
{
gender: "male",
name: "John",
location: { street: "Clement Street", country: "United States" },
skills: ["engineering", "underwater"],
},
{
gender: "female",
name: "Mary",
location: { street: "5th Avenue", country: "Spain" },
skills: ["confidence", "optics"],
},
{
gender: "male",
name: "David",
location: { street: "Vermont Ave", country: "France" },
skills: ["cards", "metalurgy", "confidence"],
},
{
gender: "female",
name: "Rachel",
location: { street: "Vermont Ave", country: "France" },
skills: ["disguise", "electrical"],
},
{
gender: "female",
name: "Muriel",
location: { street: "Vermont Ave", country: "Germany" },
skills: ["flight", "surveillance"],
},
],
checkUser (filter, to_check) {
if (Array.isArray(filter))
{
return Array.isArray(to_check)
? filter.some(val => to_check.includes(val)) // if what we're checking is an array
: filter.includes(to_check); // otherwise it's a singular value
}
else
{
const all_checks = []; // this is to save every return value from the recursive function
for (let key in filter) // going through each key in the filter
{
const checked = this.checkUser(filter[key], to_check[key]) // passing two values, which will be compared with each other
all_checks.push(checked) // pushing the checked result
}
return all_checks.every(val => val) // checking that it passes the filter by ensuring every value is true
}
},
filterData () {
let filter = this.filter
return this.users.filter(user => this.checkUser(filter, user))
},
};
// filtering.filterData(filtering.filter);
// filtering.checkUser(filtering.filter, filtering.users[0])
const result = filtering.filterData()
console.log(result)
Bit complex data structure, you should clean. However, solved what expected.
const mergeFilter = (item, [key, value]) => {
let val = Array.isArray(item[key]) ? item[key] : [item[key]];
let m = value[0];
if (typeof value === "object" && !Array.isArray(value)) {
const k2 = Object.keys(value);
val = item[key][k2];
m = value[k2][0];
}
return val.includes(m);
};
const filterData = (users, filter) => {
const filters = Object.entries(filter);
const result = users.reduce((arr, item) => {
let found = filters.every(mergeFilter.bind(null, item));
if (found) arr.push(item);
return arr;
}, []);
return result;
};
var filtering = {"filter":{"gender":["female"],"location":{"country":["Spain"]},"skills":["optics"]},"users":[{"gender":"male","name":"John","location":{"street":"Clement Street","country":"United States"},"skills":["engineering","underwater"]},{"gender":"female","name":"Mary","location":{"street":"5th Avenue","country":"Spain"},"skills":["confidence","optics"]},{"gender":"male","name":"David","location":{"street":"Vermont Ave","country":"France"},"skills":["cards","metalurgy","confidence"]},{"gender":"female","name":"Rachel","location":{"street":"Vermont Ave","country":"France"},"skills":["disguise","electrical"]},{"gender":"female","name":"Muriel","location":{"street":"Vermont Ave","country":"Germany"},"skills":["flight","surveillance"]}]}
const result = filterData(filtering.users, filtering.filter);
console.log(result)
I have an array that looks like this one (it has more objects, but the structure is the same):
[
{
especiality: "surgery",
users: [
{
id: "182",
country: "Colombia",
province: "Bogota",
telephone: "211112212",
neighbourhood: "La Santa"
region: "South",
},
{
id: "182",
country: "Venezuela",
province: "Caracas",
telephone: "322323333",
region: "North",
},
{
id: "183",
country: "Brasil",
telephone: "23232333",
neighbourhood: "Santos"
region: "South",
},
]
},
I want the addresses, if the ID is the same, to compose one single array (I need to map these elements). The outlook should look like this one:
user: [{id: 182, locations[(if they exist)
country: "Colombia",
province: "Bogota",
telephone: "211112212",
neighbourhood: "La Santa"
region: "South"], [country: "Venezuela",
province: "Caracas",
telephone: "322323333",
region: "North"],}]
I´m currently trying this, but it´s not working at all:
getGroups = test => {
_.chain(test)
.groupBy("id")
.toPairs()
.map(item => _.zipObject(["id", "country", "province", "neighbourhood", "region"], item))
.value();
return test
}
What am I doing wrong and how can I account for values that may not be available in all objects?
After grouping the items by the id, map the groups, and create an object with the id, and the items of the group as locations. Map the locations, and use _.omit() to remove the id from them.
I'm not sure about how you want to handle the outer array. I've used _.flatMap() to get a single array of users, but there's a commented option if you need to maintain the original structure.
getGroups = test =>
_(test)
.groupBy("id")
.map((locations, id) => ({
id,
locations: _.map(locations, l => _.omit(l, 'id'))
}))
.value();
const data = [{"especiality":"surgery","users":[{"id":"182","country":"Colombia","province":"Bogota","telephone":"211112212","neighbourhood":"La Santa","region":"South"},{"id":"182","country":"Venezuela","province":"Caracas","telephone":"322323333","region":"North"},{"id":"183","country":"Brasil","telephone":"23232333","neighbourhood":"Santos","region":"South"}]}];
const result = _.flatMap(data, ({ users }) => getGroups(users));
/** maintains the original structure
const result = _.map(data, ({ users, ...rest }) => ({
...rest,
users: getGroups(users)
}));
**/
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
I have an array of objects and the definition for an object looks something like this:
export class AccountInfo {
accountUid: string;
userType: string;
firstName: string;
middleName: string;
lastName: string;
}
NOTE: The reason I don't have userType as an enum is because the object is populated by a database call and I couldn't figure out a clean way to have the string returned from the db populate the enum.
I want to sort the array so that objects with a userType of 'STAFF' appear first, followed by 'TEACHER', then 'PARENT', then 'STUDENT'.
You can store the order in an array, then just use indexOf with sort to achieve your goal. See the code example below:
const humans = [{
accountUid: "1",
userType: "TEACHER",
}, {
accountUid: "2",
userType: "STAFF",
}, {
accountUid: "3",
userType: "STUDENT",
}, {
accountUid: "4",
userType: "PARENT",
}];
const order = ['STAFF', 'TEACHER', 'PARENT', 'STUDENT'];
const result = humans.sort((a, b) => order.indexOf(a.userType) - order.indexOf(b.userType));
console.log(result)
If you can't use ES6, just use:
humans.sort(function(a, b){
return order.indexOf(a.userType) - order.indexOf(b.userType);
});
Here is another way to do it, probably have an order object to store the orders
const actionOrder = {
"EAT" : 1,
"SLEEP" : 2,
"PLAY" : 3,
} as const;
const users = [{
name: "Mike",
action: "PLAY"
}, {
name: "John",
action: "EAT"
}, {
name: "Harry",
action: "SLEEP"
}
];
users.sort((a,b) => {
return actionOrder[a.action] - actionOrder[b.action];
});
console.log(users);