Searching through array of objects that contain arrays of objects efficiently - javascript

I am currently searching through an array of objects that contains an array of objects, the data structure looks like the following:
const category = 'general'
const field = 'rating'
const schema = {
categories: [
{
name: 'general',
label: 'General',
fields: [
{
name: 'id',
label: 'Market Street ID',
type: 'string'
},
{
name: 'rating',
label: 'Rating',
type: 'number'
}
]
},
{
name: 'location',
label: 'Location',
fields: [
{
name: 'search',
label: 'Query Parameters',
type: 'string'
}
]
}
]
}
The expected result is to search through the categories array for a given category name (in this case 'general') and then search through the fields for a given field name (in this case 'rating') and return the type associated with the field. I have achieved this by doing the following:
const type = schema.categories
.filter((cat) => cat.name === category)
.map((cat) => {
const fieldData = cat.fields.find((f) => f.name === field)
return fieldData.type
})
console.log(type[0])
I am wondering if there is a more efficient way to search through the array of objects within an array of objects, possibly with the type not being returned in an array

If you only need the first match, you can use Array#find along with optional chaining.
const category="general",field="rating",schema={categories:[{name:"general",label:"General",fields:[{name:"id",label:"Market Street ID",type:"string"},{name:"rating",label:"Rating",type:"number"}]},{name:"location",label:"Location",fields:[{name:"search",label:"Query Parameters",type:"string"}]}]};
const type = schema.categories.find(cat => cat.name === category)
?.fields.find(f => f.name === field).type;
console.log(type);

Related

How to use reduce with typescript to populate a typed array?

I have an array of objects which is populated with objects generated by a reduce loop. These objects already have a type, hence I need the object generated by reduce to have the same type, but I'm strugling with the initial value of the reduce, since it is an empty object.
How can I set a type to the initial object without getting an error saying that the object is missing properties?
Interface and base value:
const productFormLocal = [
{
field: 'id',
config: {
elementType: false,
value: '',
validation: {},
valid: true,
touched: false
}
},
{
field: 'nome',
config: {
elementType: 'input',
elementConfig: {
type: 'text',
placeholder: 'Nome do Produto',
name: 'nome',
},
label: 'Nome do Produto',
value: '',
validation: {
required: true,
},
valid: false,
touched: false
}
}
]
interface ProductsList {
id: number
nome: string
qtde: number
valor: number
valorTotal: number
}
const productsList: ProductsList[] = []
For instance, if I do that I get the reduce working fine, but I wouldn't be able to push the generated objects to the array:
const data: Record<string, any> = {}
const productValues = productFormLocal.reduce((obj, item) => (
obj[item.field] = item.config.value, obj
), data)
productsList.push(productValues)
And if I do that I would get an error saying that data is missing the ProductList properties:
const data: ProductsList = {}
const productValues = productFormLocal.reduce((obj, item) => (
obj[item.field] = item.config.value, obj
), data)
productsList.push(productValues)
How could I solve this? I looked a lot but I coudn't find a way to get this right.
I know I could set all properties of ProductsList as optional, but it doesn't seem to be the best approach.
Set the reduce generic type, which will type the default value as well as the reducer function return type.
const productValues = productFormLocal.reduce<Record<string, any>>((acc, item) => ({
...acc,
[item.field]: item.config.value
}), {})

Replace all values in an object with a specific key

My goal here is to convert all type values in the array below to the types in the object that collerate to numbers.
let obj = [
{
type: 'boolean',
name: 'coolName',
description: 'First description',
required: false
},
{
type: 'subcommand',
name: 'destroy',
description: 'Destroy something',
options: [
{
type:"integer",
name:"amount",
description:"How much would you like to destroy?",
required: true
}
]
}
]
const types = {
'subcommand':1,
'subcommandgroup':2,
'string':3,
'integer':4,
'boolean':5,
'user':6,
'channel':7,
'role':8,
'mentionable':9,
'number':10,
'attachment':11
}
I've been looking for a while and cannot find a function that also iterates through the nested object, if anyone has a way to do this please let me know.
obj.map(o => {
o.type = types[o.type]
if(o.options){
o.options.map(opt => {
opt.type = types[opt.type]
})
}
return o;
})

Sort array object based on another array in javascript

How can i sort and rearrange an array that looks like this
fields = [
{
uid: '2c2162cc-37d0-f1e3-96c2-6d9ccb50f38d',
field: new ObjectId("627f816d8443318c6aaa1220"
},
{
uid: '2aa60f96-135b-e179-2b46-516c87a877cc',
field: new ObjectId("6283cb3ca573a56e11587c46"),
}
]
to match the arrangement of this array:
order = [ '6283cb3ca573a56e11587c46', '627f816d8443318c6aaa1220' ]
Here is the output I’m looking for:
[
{
uid: '2aa60f96-135b-e179-2b46-516c87a877cc',
field: new ObjectId("6283cb3ca573a56e11587c46"),
},
{
uid: '2c2162cc-37d0-f1e3-96c2-6d9ccb50f38d',
field: new ObjectId("627f816d8443318c6aaa1220"),
}
]
findIndex and sort but I am very confused
fields.sort((a: any, b: any) => order.indexOf(a.field) - order.indexOf(b.field)) // It does not work
You need to use sort method on the array. And then compare the index of field on the order array.
const data = [
{
uid: '2aa60f96-135b-e179-2b46-516c87a877cc',
field: "6283cb3ca573a56e11587c46",
value: 'test val 6'
},
{
uid: '2c2162cc-37d0-f1e3-96c2-6d9ccb50f38d',
field: "627f816d8443318c6aaa1220",
value: ''
}
]
const order = [ '6283cb3ca573a56e11587c46', '627f816d8443318c6aaa1220' ];
data.sort((a,b) => order.indexOf(a.field) - order.indexOf(b.field));
console.log(data);
Notice: ObjectId class is not defined here, so I changed it to string here for simplicity.

How to retrieve certain properties of an array of objects and put it into a new array of objects? [duplicate]

This question already has answers here:
Filter array of objects based on another array in javascript
(10 answers)
Closed 2 years ago.
i have an array of objects like below,
data: [
{
name: 'name1',
id: '1',
description: 'name 1 description',
},
{
name: 'name2',
id: '2',
description: 'name 2 description',
},
{
name: 'name3',
id: '3',
description: 'name 3 description',
},
]
i have an array consisting of ids like so
const id_list = ['1','2'];
Now i want to retrieve the id and name from data array object whose id matches with id_list
so the expected output is
const new = [
{
id: '1',
name: 'name1',
},
{
id: '2',
name: 'name2',
}
]
i am new to using react, javascript or typescript. could someone help me solve this. thanks.
what i have tried?
i know that to filter the value based on one value
so if i have to filter based on one id say '1'
i can do
const new = data.filter((item) => id === item.id);
but in my case i want to filter all items which match the id_list array and should retrieve only matching object name and id and put it to a array.
You can use the map function with a find method to map every id of id_list to the corresponding object in data
const result = id_list.map((id) => data.find((d) => d.id === id));
After that you have all objects that were found by ids in result. You can either only use the props you want or map again and get only the required properties.
const final = result.map(({ id, name })=> ({ id, name }))

Dynamic array filtering by object property

I have a react live search dropdown component that filters through an array of objects by a search term. It filters my objects by title and then returns a list of all the related objects. This works fine.
Current:
Data Structure
data: [
{ id: 1, title: 'Some title here' },
{ id: 2, title: 'Another title' },
{ id: 3, title: 'last title' },
]
Component
<LiveSearch
term={term}
data={data} />
Inside Live search component
Filter data by term and render list
return data
.filter(item => item.title.toLowerCase().includes(term.toLowerCase())
.map((item, idx) => <li key={idx}>{item.title}</li>
My objects to search by are getting more advanced and what I would like to be able to do is pass into my component an array of property names I would like to compare to the search term.
My thinking process behind it is to loop through the object properties and if on of the properties matches the term the loop breaks and returns true adding that object to the list of items to be displayed.
Goal
Data Structure
data: [
{ id: 1, country: 'Canada', title: 'Some title here' },
{ id: 2, country: 'Australia', title: 'Another title' },
{ id: 3, country: 'Netherlands', title: 'last title' },
]
Component
<LiveSearch
searchFields={['country', 'title']}
term={term}
data={data} />
Inside Component filtering
return data
.filter(item => {
// Dynamic filtering of terms here
})
.map((item, idx) => <li key={idx}>{item.title}</li>
Inside the filter I'm trying to get a loop through the array and dynamically produce logic similar to this
item.searchFields[0].toLowerCase().includes(term.toLowerCase()) ||
item.searchFields[1].toLowerCase().includes(term.toLowerCase())
But obviously could loop over an infinite number of searchfields/properties
Use Array#some()
Something like
term = term.toLowerCase()
return data
.filter(item => {
return searchFields.some(field => item[field].toLowerCase().includes(term))
}).map(...
Check if some of the searchFields match:
// Checks wether a value matches a term
const matches = (value, term) => value.toLowerCase().includes(term.toLowerCase());
// Checks wether one of the fields in the item matcues the term
const itemMatches = (fields, term) => item => fields.some(field => matches(item[field], term);
// Filter the data to only contain items where on of the searchFields matches the term
const result = props.data.filter( itemMatches(props.searchFields, props.term) );
return result.map(item => <li key={idx}>{item.title}</li>);
You can use Array .some combined with .filter
let result = data.filter(obj =>
searchFields.some(s =>
obj[s] != undefined && obj[s].toLowerCase() === term
));
let data = [
{ id: 1, country: 'Canada', title: 'Some title here' },
{ id: 2, country: 'Australia', title: 'Another title' },
{ id: 3, country: 'Netherlands', title: 'last title' },
], searchFields = ["country", "title"], term = "canada";
let result = data.filter(obj =>
searchFields.some(s =>
obj[s] != undefined && obj[s].toLowerCase() === term
));
console.log(result);

Categories

Resources