I am trying to create a new array.
I have list of plugins with different versions, and I need to find plugins with same uniqueIdentifier but different versions, and create one array out of it.
Example:
{
"uniqueIdentifier": "theme_test",
"version": "2011120800"
},
{
"uniqueIdentifier": "theme_test",
"version": "3011120800"
},
{
"uniqueIdentifier": "theme_test",
"version": "4011120800"
},
to be like this:
{
"uniqueIdentifier": "theme_test",
"version": [
"2011120800",
"3011120800",
"4011120800"
]
}
So, in my code I am getting all the information, but I cannot make it work to store this versions as an array. So I am checking the uniqueIdentifier and then the version, and trying to generate new array:
item.pluginVersions.items.forEach(function(plugin) {
pluginVersionsSupported.forEach(function(supportedPlugin) {
if (plugin.uniqueIdentifier === supportedPlugin.uniqueIdentifier) {
if (plugin.version == supportedPlugin.version) {
pluginData = {
uniqueIdentifier: plugin.uniqueIdentifier,
version: []// need to update this to be an array
}
}
}
})
I appreciate all the help.
you need to use Array.reduce method:
const data =
[ { uniqueIdentifier: 'theme_test', version: '2011120800' }
, { uniqueIdentifier: 'theme_test', version: '3011120800' }
, { uniqueIdentifier: 'theme_test', version: '4011120800' }
]
const result = Object.values(data.reduce( (r,{uniqueIdentifier,version}) =>
{
r[uniqueIdentifier] ??= { uniqueIdentifier, version:[] }
r[uniqueIdentifier].version.push(version)
return r
},{}))
console.log(result)
Assuming you only have one pluginData: move the new object out of the loop so that it doesn't get created repeatedly, and in the loop push the version to the existing array.
pluginData = {
uniqueIdentifier: plugin.uniqueIdentifier,
version: []
}
item.pluginVersions.items.forEach(function(plugin) {
...
if (plugin.version == supportedPlugin.version) {
pluginData.version.push(plugin.version);
You may also use Array#reduce() and Object.entries() as follows:
const data = [{"uniqueIdentifier": "theme_test","version": "2011120800"},{"uniqueIdentifier": "theme_test","version": "3011120800"},{"uniqueIdentifier": "theme_test","version": "4011120800"}];
const groupedData = Object.entries(
data.reduce(
(prev, {uniqueIdentifier,version}) =>
({ ...prev, [uniqueIdentifier]:(prev[uniqueIdentifier] || []).concat(version) }), {}
)
)
.map(([uniqueIdentifier,version]) => ({uniqueIdentifier,version}));
console.log( groupedData );
Related
I'm trying to convert an object into single array with just key and value. I tried two different ways. Though I succeeded in my first attempt but using reduce I am unable to get the result. Please kindly let me know if there is/are better ways of achieving the same. Thank you.
var demoArr = [
{
"results": [
{
"listing_id": 10544193
},
{
"listing_id": 4535435
}
],
"results1": [
{
"listing_id": 1054419363
},
{
"listing_id": 432535435
}
]
}
];
let aaa = [];
// demoArr.map(x => { (before)
demoArr.forEach(x => { //(after)
let ss = Object.values(x);
// ss.map(y => { (before)
ss.forEach(y => { //(after)
y.forEach(k => {
aaa.push({"listing_id" : k.listing_id});
})
});
});
Resulted in the following.
[{"listing_id":10544193},{"listing_id":4535435},{"listing_id":1054419363},{"listing_id":432535435}]
Is there a better way to achieve the above? Maybe by using reduce? I tried but failed to get the result.
var ds = demoArr.reduce((a,value) => {
a[value.listing_id] = a[value.listing_id] ? a[value.listing_id] : value
return a
},{});
Here's one way use flatMap() and Object.values, then flatten the result. Using Object.values as an argument in this fashion is a shorthand for applying the map argument directly into the Object.values method and returning the result
var demoArr = [{
"results": [{
"listing_id": 10544193
},
{
"listing_id": 4535435
}
],
"results1": [{
"listing_id": 1054419363
},
{
"listing_id": 432535435
}
]
}];
let output = demoArr.flatMap(Object.values).flat();
console.log(output)
I am using eslint and getting this error.
Expected to return a value in arrow function
The error is showing on the third line of the code.
useEffect(() => {
let initialPrices = {};
data.map(({ category, options }) => {
initialPrices = {
...initialPrices,
[category]: options[0].price,
};
});
setSelectedPrice(initialPrices);
}, []);
The map function must return a value. If you want to create a new object based on an array you should use the reduce function instead.
const reducer = (accumulator, { category, options }) => (
{...accumulator, [category]:options[0].price}
)
const modifiedData = data.reduce(reducer)
More information https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
The map function is intended to be used when you want to apply some function over every element of the calling array. I think here it's better to use a forEach:
useEffect(() => {
let initialPrices = {};
data.forEach(({ category, options }) => {
initialPrices = {
...initialPrices,
[category]: options[0].price,
};
});
setSelectedPrice(initialPrices);
}, []);
Your map function should return something. Here it's not the case so the error happens. Maybe a reduce function will be more appropriate than map?
From what I can see in your case, is that you want to populate initialPrices, and after that to pass it setSelectedPrice. The map method is not a solution, for you in this case, because this method returns an array.
A safe bet in your case would a for in loop, a forEach, or a reduce function.
const data = [
{
category: "ball",
options: [
{
price: "120.45"
}
]
},
{
category: "t-shirt",
options: [
{
price: "12.45"
}
]
}
];
The forEach example:
let initialPrices = {};
// category and options are destructured from the first parameter of the method
data.forEach(({ category, options}) => {
initialPrices[category] = options[0].price;
});
// in this process I'm using the Clojure concept to add dynamically the properties
setSelectedPrice(initialPrices);
The reduce example:
const initialPrices = Object.values(data).reduce((accumulatorObj, { category, options}) => {
accumulatorObj[category] = options[0].price
return accumulatorObj;
}, {});
setSelectedPrice(initialPrices);
I am having the JSON array of objects like below,
let data = [
{
"node":[
{
"name":"aaaaa",
"count":"2",
}
]
},
{
"client":[
{
"name":"bbbbb",
"count":"2",
}
]
},
{
"ip_address":[
{
"name":"ccccc",
"count":"3",
}
]
},
{
"compute":[
{
"name":"dddd",
"count":"1",
}
]
}
]
let find_key = "ip_address";
Need to check whether the root key is exists or not(for example need to find ip_address is exists or not). without foreach please.
JSFiddle Link : https://jsfiddle.net/b9gxhnko/
Tried the following ways but no luck. Some help would be appreciated. Thanks in advance.
Tried like below, but its not working (always returning false),
console.log(data[0].has(find_key)); // false
console.log(data.has(find_key)); // false
console.log(data[0].hasOwnProperty(find_key)); // false
You can try with array.some():
let exists = data.some(x => x[find_key]);
let data = [
{
"node":[
{
"name":"aaaaa",
"count":"2",
}
]
},
{
"client":[
{
"name":"bbbbb",
"count":"2",
}
]
},
{
"ip_address":[
{
"name":"ccccc",
"count":"3",
}
]
},
{
"compute":[
{
"name":"dddd",
"count":"1",
}
]
}
]
let find_key = "ip_address";
let exists = data.some(x => x[find_key]);
console.log(exists);
You have an array of objects, and _.has() an the in expect as single object. Right now you check if the array has a key called ip_address, which it doesn't. Use Array.some() or lodash's _.some(), and check if each object has the key:
const data = [{"node":[{"name":"aaaaa","count":"2"}]},{"client":[{"name":"bbbbb","count":"2"}]},{"ip_address":[{"name":"ccccc","count":"3"}]},{"compute":[{"name":"dddd","count":"1"}]}]
// vanilla JS
const result1 = data.some(o => 'ip_address' in o)
console.log(result1)
// lodash
const result2 = _.some(data, o => _.has(o, 'ip_address'))
console.log(result1)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
So,
I am receiving the data that has the following information:
{
"data":[
{
"vote_count":22222,
"id":299537,
"ready":false,
},
{
"vote_count":2850,
"id":299534,
"ready":true,
},
]
}
Now I need to make a new object that would contain the same structure but with some properties, ie:
{
"data": [
{
"ready":false,
},
{
"ready":true,
}
]
}
I need the solution that is scalable, imagine having a set of data with 50 properties for example. Also, I did find solutions with objects, but never with array of objects.
Thanks guys, I've been busting my head for three hours now.
You could use destrcuturing and shorthand property names to create new objects like this:
const input={"data":[{"vote_count":22222,"id":299537,"ready":false,},{"vote_count":2850,"id":299534,"ready":true,},]}
const data = input.data.map(({ ready }) => ({ ready }))
console.log({ data })
If you want to get a bunch of properties, you could create an array of properties you need. Then use Object.assign() or reduce to create a subset of each object like this:
const input={"data":[{"vote_count":22222,"id":299537,"ready":false,},{"vote_count":2850,"id":299534,"ready":true,},]}
const properties = ["vote_count", "ready"]
const data = input.data.map(a =>
Object.assign({}, ...properties.map(p => ({ [p]: a[p] })))
)
/* You could also use reduce like this:
input.data.map(a => properties.reduce((r, p) => ({ ...r, [p]: a[p] }), {}))
*/
console.log({ data })
Map the properties you want
var obj1 = {
"data":[
{
"vote_count":22222,
"id":299537,
"ready":false,
},
{
"vote_count":2850,
"id":299534,
"ready":true,
},
]
}
var obj2 = {}
obj2.date = obj1.data.map(data => ({ ready: data.ready}));
console.log(obj2)
You can do it using Array#map method and Array#reduce method
const input = {
"data": [{
"vote_count": 22222,
"id": 299537,
"ready": false,
},
{
"vote_count": 2850,
"id": 299534,
"ready": true,
},
]
}
const extract = ['ready']
const data = input.data.map(o => extract.reduce((obj, k) => (obj[k] = o[k], obj), {}))
console.log({ data })
I have a data structure that looks like this:
{
sections: [
{
pages: [
{
questions: [
],
},
],
},
],
}
There's data in the questions array that I'm trying to get at, and return a final 1 dimensional array at the end. There can be an x number of sections, each section can have an x number of pages, and each page can have an x number of questions.
I'm trying to keep the code relatively concise but also readable, this is my current implementation:
function generateQuestionData(survey) {
let data = [];
survey.sections.forEach((section) => {
section.pages.forEach((page) => {
const newData = page.questions.map(getQuestionDataItem);
data = [...data, ...newData];
});
});
return data;
}
EDIT
Is there a way to accomplish the same thing without the data variable reassignment? so something along the lines of
function generateQuestionData(survey) {
return survey.sections.forEach((section) => { // something instead of forEach
section.pages.forEach((page) => page.questions.map(getQuestionDataItem));
// data = [...data, ...newData]; no need for this?
});
}
if that makes sense
How about having a helper for iteration:
function* goOver(array, key, ...keys) {
for(const el of array) {
if(keys.length) {
yield* goOver(el[key] || [], ...keys);
} else {
yield el[key];
}
}
That can be used as:
const result = [...goOver(survey.sections, "pages", "questions")]
.map(getQuestionDataItem);
concerning the second question:
Is there a way to accomplish the same thing without the data variable reassignment?
how about:
data.push(...newData);
You could use reduce in order to show the intent to really do something per section and page to the likes of:
private generateQuestionData = (survey) =>
survey.sections.reduce((data, section) =>
[
...data,
...section.pages.reduce((pageData, page) =>
[
...pageData,
...page.questions.map(getQuestionDataItem)
],
[]
)
],
[]
);
Code indentation/formatting could surely be optimized.
const data = {
sections: [
{
pages: [
{
questions: [
"hello",
"world"
],
},
{
questions: [
"foo",
"bar"
]
}
],
},
],
};
const get = (...pathKeys) => o => pathKeys.reduce((o,k ) => o[k], o);
const flatten = (arrays) => [].concat.apply([], arrays);
const result = flatten(get("sections")(data).map(s => get("pages")(s).map(get("questions"))));
console.log(flatten(flatten(result)));
Note that the flatten at the end could be simplified with a flattenDeep function.
In "pseudo code" I would express your problem like that, with
compose being composition left to right, and map being fn => arr => arr.map(fn)
compose(
get("section"),
map(compose(get("pages"), map(get("questions")))),
flattenDeep,
);