I have an object like this:
{
"idMeal": "52795",
"strMeal": "Chicken Handi",
"strDrinkAlternate": null,
"strCategory": "Chicken",
"strArea": "Indian"
}
I am trying to get the value of other items(i.e. strMeal and strCategory) using the value of "idMeal". How can I do that?
As far as i understood you want to filter an list of food objects, just put them in an array and filter like this:
[obj1, obj2, obj3].filter(o => o.idMeal="52795")
First you should have stated what you tried. Then, you can use a simple condition:
let cat;
let area;
if (obj.idMeal === myValue) {
cat = obj.strCategory;
area = obj.strArea;
}
There are way more ways of doing this. Take a look at .map(), .filter() but those are for arrays.
The easiest way to achieve this is to filter the data based on the key-value pair and then reduced the requested fields into a new object.
const mealData = [{
"idMeal": "52795",
"strMeal": "Chicken Handi",
"strDrinkAlternate": null,
"strCategory": "Chicken",
"strArea": "Indian",
}];
const filterAndMap = (data, key, value, fields) =>
data
.filter((record) => record[key] === value)
.map(record => fields.reduce((acc, field) =>
({ ...acc, [field]: record[field] }), {}));
const result = filterAndMap(mealData, 'idMeal', '52795', ['strMeal', 'strCategory']);
console.log(result);
Alternatively, you could pass a filter function and a mapper function:
const mealData = [{
"idMeal": "52795",
"strMeal": "Chicken Handi",
"strDrinkAlternate": null,
"strCategory": "Chicken",
"strArea": "Indian",
}];
const filterAndMap = (data, filterFn, mapperFn) =>
data.filter(filterFn).map(mapperFn);
const result = filterAndMap(
mealData,
({ idMeal }) => idMeal === '52795',
({ strMeal, strCategory }) => ({ strMeal, strCategory }));
console.log(result);
In the example above, we can remove the filterAndMap function and just chain filter and map directly.
const mealData = [{
"idMeal": "52795",
"strMeal": "Chicken Handi",
"strDrinkAlternate": null,
"strCategory": "Chicken",
"strArea": "Indian",
}];
const result = mealData
.filter(({ idMeal }) => idMeal === '52795')
.map(({ strMeal, strCategory }) => ({ strMeal, strCategory }));
console.log(result);
Related
I'm merging two objects together to create a filter object. However I want to group the merged objects property values where the keys are the same.
So...
[{category: 'furniture'}, {category: 'mirrors'}, {availability: 'in_stock'}]
becomes
[{category: ['furniture', 'mirrors']}, {availability: 'in_stock'}]
any ideas?
With lodash you merge the entire array to a new object by spreading into _.mergeWith(). The customizer should use empty arrays as default values for the current values, and concat the values. Use _.map() to convert back to an array.
const data = [{category: 'furniture'}, {category: 'mirrors'}, {availability: 'in_stock'}];
const result = _.map(
_.mergeWith({}, ...data, (a = [], b = [], key) => a.concat(b)),
(val, key) => ({ [key]: val })
)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG+ljU96qKRCWh+quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
Using vanilla JS, reduce the array to a Map using the objects' keys as the keys of the Map, with an empty array as the value, and push the objects' values into the arrays. Use Array.from() to convert the Map to an array.
const data = [{category: 'furniture'}, {category: 'mirrors'}, {availability: 'in_stock'}];
const result = Array.from(
data.reduce((acc, obj) => {
Object.entries(obj)
.forEach(([key, val]) => {
if(!acc.has(key)) acc.set(key, [])
acc.get(key).push(val)
})
return acc
}, new Map()),
([key, val]) => ({ [key]: val })
)
console.log(result)
You can use reduce like this:
const data = [
{ category: 'furniture' },
{ category: 'mirrors' },
{ availability: 'in_stock' }
];
const result = data.reduce(
(a, x) => {
const key = Object.keys(x)[0]; // find the key of the current object
if (!a.tmp[key]) { // if the current key doesn't exist in the lookup object (tmp) yet ...
a.tmp[key] = []; // create an empty array in the lookup object for the current key
a.result.push({ [key]: a.tmp[key] }); // push the current object to the result
}
a.tmp[key].push(x[key]); // push the current value to the array
return a;
},
{ result: [], tmp: {} },
).result;
console.log(result);
I'm sure there are easier ways to achieve this, but that's the best I can come up with right now.
we can also achieve this by using forEach loop :
const input = [{category: 'furniture'}, {category: 'mirrors'}, {availability: 'in_stock'}];
const resultObj = {};
const resultArr = [];
input.forEach((obj) => {
resultObj[Object.keys(obj)[0]] = [];
})
input.forEach((obj) => {
resultObj[Object.keys(obj)[0]].push(obj[Object.keys(obj)[0]]);
resultArr.push(resultObj);
})
console.log([...new Set(resultArr)]);
Another one reduce solution
const arr = [{category: 'furniture', category2: 'furniture2'}, {category: 'mirrors'}, {availability: 'in_stock'}]
const result = Object.values(arr
.flatMap((obj) => Object.entries(obj))
.reduce((acc, [key, value]) => {
acc[key] = acc[key]
? {[key]: [...acc[key][key], value] }
: {[key]: [value] }
return acc;
}, {}));
console.log(result)
.as-console-wrapper{min-height: 100%!important; top: 0}
A generic implementation could achieve a merger of any kind of objects regardless of amount and kind of an(y) object's property names.
Since the result of such an implementation is an object, one needs additional treatment in order to cover the OP's requirement(s).
function mergeAndCollectItemEntries(result, item) {
// return the programmatically aggregated merger/result.
return Object
// get an item's entry array.
.entries(item)
// for each key-value pair ...
.reduce((merger, [key, value]) => {
// ... access and/or create a `key` specific array ...
// ... and push `value` into this array.
(merger[key] ??= []).push(value);
// return the programmatically aggregated merger/result.
return merger;
}, result);
}
const sampleData = [
{ category: 'furniture' },
{ category: 'mirrors' },
{ availability: 'in_stock' },
];
const mergedData = sampleData
.reduce(mergeAndCollectItemEntries, {});
const mergedDataList = Object
.entries(
sampleData
.reduce(mergeAndCollectItemEntries, {})
)
.map(entry => Object.fromEntries([entry]));
//.map(([key, value]) => ({ [key]: value }));
console.log({
sampleData,
mergedData,
mergedDataList,
});
console.log(
Object
.entries([
{ category: 'furniture', foo: 'baz' },
{ category: 'mirrors', bar: 'bizz' },
{ availability: 'in_stock', bar: 'buzz' },
].reduce(
mergeAndCollectItemEntries, {}
)
).map(
([key, value]) => ({ [key]: value })
//entry => Object.fromEntries([entry])
)
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Another approach here with building an tracking object to merge the values.
Handle the cases of single value keep as string and multiple values as array per the expected output.
const merge = (arr, output = {}) => {
arr.forEach((item) => {
const [[key, val]] = Object.entries(item);
if (key in output) {
output[key] = Array.isArray(output[key])
? output[key].concat(val)
: [output[key]].concat(val);
} else {
output[key] = val;
}
});
return Object.entries(output).map(([key, val]) => ({ [key]: val }));
};
const data = [
{ category: "furniture" },
{ category: "mirrors" },
{ availability: "in_stock" },
];
console.log(merge(data));
I am creating searchbar to filter key value data objects. I am getting filter is not a function error while doing search. Is there any other function to filter in key value pair objects ?
Data :-
{
meta_city : {
label: "City"
values: (5) ["DL", "KA", "GJ", "MH", "UP"]
},
meta_country : {
label: "Country"
values: (5) ["IN", "US", "CA"]
}
}
Handle search (filterData data is local state) :-
const handleSearchFilter = (event) => {
const searchWord = event.target.value;
const newFilter = Object.keys(filterData).map((key) => {
filterData[key].filter((value) => {
return value.includes(searchWord);
});
});
setFilterData(newFilter);
};
<div className="mp-input-field-container">
<input
className="mp-input"
placeholder="Search"
onChange={handleSearchFilter}
/>
</div>
You should use reduce like this:
const handleSearchFilter = (event) => {
const searchWord = event.target.value;
const newFilter = Object.keys(filterData).reduce((result, key) => {
if (filterData[key].values.includes(searchWord)) {
result.push(filterData[key]);
};
return result;
}, []);
setFilterData(newFilter);
};
In this example I'm returning an array result. you can return an object if you want.
Filter does not exist on a string type. When filterData[key] is called, key has a value of label. filterData["label"] returns a string "City".
try
const searchWord = (word) => Object.values(filterData).filter((data) => data.values?.includes(word));
const handleSearchFilter = (event) => {
const word = event.target.value;
const [newFilter] = searchWord(word)
setFilterData(newFilter);
}
searchWord returns if you search "DL"
[
{
label: 'City',
values: [ 'DL', 'KA', 'GJ', 'MH', 'UP' ]
}
]
Was that the result you were looking for?
Here is the code snippet to prove the solution works:
var filterData = {
meta_city : {
label: "City",
values: ["DL", "KA", "GJ", "MH", "UP"]
},
meta_country : {
label: "Country",
values: ["IN", "US", "CA"]
}
}
const searchWord = (word) => Object.values(filterData).filter((data) => data.values.includes(word));
console.log(searchWord("DL"))
If I have an object
post = {
title: "Title",
image_1: "1234",
image_2: "2345"
}
and I want to get an array:
["1234", "2345"]
This is how I filter attributes to be included in the array
Object.keys(post).filter(key =>
key.includes("image")
);
and get an array of correct keys. How do I get values instead?
One way is to just do your filter then map the object lookup:
Object.keys(post)
.filter(key => key.includes("image"))
.map(key => post[key])
Or, use Object.entries to get both keys and values:
Object.entries(post)
.filter(([key, value]) => key.includes("image"))
.map(([key, value]) => value)
Or, with a "filter and map" operation:
Object.entries(post)
.flatMap(([key, value]) => key.includes("image") ? [value] : [])
You can use Object.entries to get a list of key-value pairs, and .forEach to iterate over it:
const post = {
title: "Title",
image_1: "1234",
image_2: "2345"
};
const res = [];
Object.entries(post).forEach(([key,value]) => {
if(key.includes("image")) res.push(value);
});
console.log(res);
const post = { title: "Title", image_1: "1234", image_2: "2345" };
const keys = Object.keys(post).filter(key => key.includes("image"));
const output = keys.map(key => post[key]);
console.log(output); // [ '1234', '2345' ]
You could use reduce method on Object.entries and check if the key startsWith a specific string.
const post = {
title: "Title",
image_1: "1234",
image_2: "2345"
}
const result = Object
.entries(post)
.reduce((r, [k, v]) => {
if (k.startsWith('image')) r.push(v);
return r;
}, [])
console.log(result)
Object.entries to obtain entries, then filter those which starts with image:
let post={title:"Title",image_1:"1234",image_2:"2345"};
let result = Object.entries(post)
.filter(e => e[0].startsWith('image'))
.flatMap(e => e[1])
console.log(result)
I have an array of objects
const data = [{
Description: "confirm"
Id: "1"
Name: "confirm"
Value: "VIP:confirm"
}, {
Description: "validate"
Id: "2"
Name: "validate"
Value: "VIP:validate"
}, {
Description: "Sent"
Id: "2"
Name: "Sent"
Value: "VIP:Sent"
}]
Now, I am trying to get the description by passing the value:
const valuesObject = [
"VIP:Confirmed",
"VIP:Validated",
"VIP:Sent"
]
Now, Values data is like
const getDescription = (
value: string,
Values: Array < >
) => {
let allValues = _.find(Values, item => item.Value === value)
return resolve(allValues)
}
const resolve = (object) => {
return object?.Description ? object.Description : object?.Name ?? ''
}
Now, here I am doing ,
const status = valuesObject.map((value) => {
return getDescription(value, data)
})
return status.join('/')
I was expecting it should return me Confirmed/Validated/Sent
It returns but function gets called multiple times. can any one help me with this ?
Use _.intersectionWith() to get objects with the Value property that matches one of an array of values. Then map to get the Description or Name:
const getDescription = (arr, values) => _.map(
_.intersectionWith(arr, values, (o, v) => o.Value === v), // get all objects with matching values
({ Description, Name = '' }) => Description || Name // map to description / name / empty string
).join('/')
const data = [{"Description":"Confirmed","Id":"1","Name":"confirm","Value":"VIP:Confirmed"},{"Description":"Validated","Id":"2","Name":"validate","Value":"VIP:Validated"},{"Description":"Sent","Id":"2","Name":"Sent","Value":"VIP:Sent"}]
const valuesObject = ["VIP:Confirmed","VIP:Validated","VIP:Sent"]
const result = getDescription(data, valuesObject)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.19/lodash.js"></script>
Using lodash/fp you can generate the getDescription() function with _.flow():
const getDescription = _.flow(
_.intersectionWith((o, v) => o.Value === v), // get all objects with matching values
_.map(({ Description, Name = '' }) => Description || Name), // map to description / name / empty string
_.join('/')
)
const data = [{"Description":"Confirmed","Id":"1","Name":"confirm","Value":"VIP:Confirmed"},{"Description":"Validated","Id":"2","Name":"validate","Value":"VIP:Validated"},{"Description":"Sent","Id":"2","Name":"Sent","Value":"VIP:Sent"}]
const valuesObject = ["VIP:Confirmed","VIP:Validated","VIP:Sent"]
const result = getDescription(data, valuesObject)
console.log(result)
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
I have an array with headers - say ["language", "name", "code"]
and an array of arrays of values - for example
[["English", "Matt", "2D"], ["Croatian", "Dana", "8S"], ["Russian", "Ivan", "2W"]].
I am trying to obtain an array of objects, like so:
[
{language: English, name: Matt, code: 2D},
{language: Croatian, name: Dana, code: 8S},
{language: Russian, name: Ivan, code: 2W}
]
Any elegant way to do this without nested for loops?
let props=["language", "name", "code"];
let data=[["English", "Matt", "2D"], ["Croatian", "Dana", "8S"], ["Russian", "Ivan", "2W"]];
let result=data.map( (innerArray) =>{let obj={};innerArray.forEach( (innerData,index) =>{obj[props[index]]=innerData;});return obj;
});
console.log(result);
const props = ["language", "name", "code"];
const values = [["English", "Matt", "2D"], ["Croatian", "Dana", "8S"], ["Russian", "Ivan", "2W"]];
const formatted = values.map(value => ({
[props[0]]: value[0],
[props[1]]: value[1],
[props[2]]: value[2],
}));
Or like this:
const formatted4 = values.map(value => {
let v = {};
props.forEach((prop, i) => {
v = {
...v,
[prop]: value[i]
}
});
return v;
});
You can create this without complexity, if the data count is constant, using ES6*
var dataList = [["English", "Matt", "2D"], ["Croatian", "Dana", "8S"], ["Russian", "Ivan", "2W"]];
let myList = [];
for([language, name, code] of dataList)
myList.push({language, name, code});
console.log(myList);
You can use array destructuring (assuming you're sure your data format stays the same) :
const newArr = [];
for(const [language, name, code] of yourDataArray){
//do whatever you want with the variables language, name, code
newArr.push({
language: language,
name: name,
code: code
})
}