I have this array of object, I want to extract its ids.
const arr = [
{
"id": "1",
},
{
"id": "2",
"options": [
{
"id": "2.1",
}
]
},
]
I did this
const one = arr.map(ob => ob.id)
const two = arr.flatMap(ob => ob.options).map(ob => ob?.id).filter(Boolean)
console.log([...one, ...two])
which worked fine, it prints ['1', '2', '2.1'] which is what I wanted but is there any simpler or shorter way to do it?
Recursive with foreach
const arr = [{
"id": "1",
},
{
"id": "2",
"options": [{
"id": "2.1",
}]
},
]
const getResult = (array, result = []) => {
array.forEach(val => {
result.push(val.id)
if (val.options) {
result = getResult(val.options, result)
}
})
return result
}
console.log(getResult(arr))
Here's one possible approach - .concat onto an array of just the parent id property inside the mapper callback.
const arr = [
{
"id": "1",
},
{
"id": "2",
"options": [
{
"id": "2.1",
}
]
},
];
const result = arr.flatMap(obj => [obj.id].concat(obj.options?.map(o => o.id) ?? []));
console.log(result);
Another is
const arr = [
{
"id": "1",
},
{
"id": "2",
"options": [
{
"id": "2.1",
}
]
},
];
const toId = obj => obj.id;
const result = arr.map(toId).concat(arr.flatMap(o => o.options?.map(toId) ?? []));
console.log(result);
This generic approach will extract all id fields, without you needing to specify the structure (such as the options key):
const arr = [{"id":"1"},{"id":"2","options":[{"id":"2.1"}]}];
const f=o=>typeof o==='object'?Object.keys(o).flatMap(k=>k==='id'?[o[k]]:f(o[k])):[];
console.log(f(arr));
Related
I need to iterate a nested value in my javascript.
My wanted output should be like this
shows: ['food.order', 'drink.order', 'play.basketball', 'play.soccer']
const results = [
{
"ID": "shops",
"Shopping": [
{
"ID": "food.order",
"Name": "Food"
},
{
"ID": "drink.order",
"Name": "Drink"
}
]
},
{
"ID": "fun",
"Sports": [
{
"ID": "play.basketball",
"Name": "Basketball"
},
{
"ID": "play.soccer",
"Name": "Soccer"
},
]
}
];
console.log(results);
const final = { shows: results.map(data => data['key'].ID) }
Your question is not clear though, but I am assuming that you are searching for ID property and want to grab the value of the ID and make an array. You can try this way-
const results = [{"ID": "shops", "Shopping": [{ "ID": "food.order", "Name": "Food"},{ "ID": "drink.order", "Name": "Drink"}]},{"ID": "fun", "Sports": [{ "ID": "play.basketball", "Name": "Basketball"},{ "ID": "play.soccer", "Name": "Soccer"}]}];
const ans = results.reduce((acc, item) => {
// Iterate throw the each item's properties
Object.values(item).forEach(val => {
// Filter out the objects which has the `ID` property and get the value of the `ID`.
const ids = typeof val === 'object' && val instanceof Array
? val.filter(x => x.ID !== undefined).map(({ID}) => ID)
: [];
acc = [...acc, ...ids];
});
return acc;
}, []);
console.log(ans);
.as-console-wrapper {min-height: 100%!important; top: 0}
Are you looking for something like this?
const results = [{"ID": "shops", "Shopping": [{ "ID": "food.order", "Name": "Food"},{ "ID": "drink.order", "Name": "Drink"}]},{"ID": "fun", "Sports": [{ "ID": "play.basketball", "Name": "Basketball"},{ "ID": "play.soccer", "Name": "Soccer"}]}];
const final = results.reduce((p, n) => {
// Get all object's array props and then reduce their keys
const mapped = Object.keys(n).filter((key) => Array.isArray(n[key])).reduce((arr, key) => [
...arr,
// Get the array by using the object's key, filter out all objects which don't have
// an 'ID' key, and return a new array which only contains the x.ID property
...n[key].filter((x) => x.ID).map((x) => x.ID)
], []);
return [
...p,
...mapped,
];
}, []);
console.log('final', final);
const results=[{ID:"shops",Shopping:[{ID:"food.order",Name:"Food"},{ID:"drink.order",Name:"Drink"}]},{ID:"fun",Sports:[{ID:"play.basketball",Name:"Basketball"},{ID:"play.soccer",Name:"Soccer"}]}];
let arr = results.flatMap(e => Object.values(e).filter(n => Array.isArray(n))) // at this stage you have an array of arrays
.flat() // at this stage you have flat array from previous stage
.map(s => s.ID) // Now you pick the IDs
console.log(arr)
// This is a large array of objects, e.g.:
let totalArray = [
{"id":"rec01dTDP9T4ZtHL4","fields":
{"user_id":170180717,"user_name":"abcdefg","event_id":516575,
}]
let uniqueArray = [];
let dupeArray = [];
let itemIndex = 0
totalArray.forEach(x => {
if(!uniqueArray.some(y => JSON.stringify(y.fields.user_id) === JSON.stringify(x.fields.user_id))){
uniqueArray.push(x)
} else(dupeArray.push(x))
})
node.warn(totalArray);
node.warn(uniqueArray);
node.warn(dupeArray);
return msg;
I'm successfully deduping the array to produce only unique values. Problem is, I need to remove both duplicates, e.g.: if there are 2 objects with the same user_id key, I want to remove both of the objects from the array, not just one.
One option is to iterate over the array and put the current object being iterated over at a user_id property on the object. If the property already exists there, reassign it to null instead. At the end, take the values of the object and remove the null values:
const totalArray = [{
"id": "rec01dTDP9T4ZtHL4",
"fields": {
"user_id": 170180717,
"user_name": "abcdefg",
"event_id": 516575,
}
}, {
"id": "rec01dTDP9T4ZtHL4",
"fields": {
"user_id": 170180717,
"user_name": "abcdefg",
"event_id": 516575,
}
}, {
"id": "unique",
"fields": {
"user_id": 1234,
"user_name": "abcdefg",
"event_id": 516575,
}
}];
const uniques = {};
for (const item of totalArray) {
const prop = item.fields.user_id;
uniques[prop] = uniques.hasOwnProperty(prop)
? null
: item;
}
const output = Object.values(uniques).filter(Boolean);
console.log(output);
You could first group the objects based on user_id. Then partition them based on group size (if a group only contains a single record it is unique). Then flatten the groups so it'll end up as a normal array of records and not an array of groups of records.
function groupBy(iterable, fn) {
const groups = new Map();
for (const item of iterable) {
const key = fn(item);
if (!groups.has(key)) groups.set(key, []);
groups.get(key).push(item);
}
return groups;
}
function partition(iterable, fn) {
const truthy = [], falsy = [];
for (const item of iterable) {
(fn(item) ? truthy : falsy).push(item);
}
return [truthy, falsy];
}
const totalArray = [{
"id": "rec01dTDP9T4ZtHL4",
"fields": {
"user_id": 170180717,
"user_name": "abcdefg",
"event_id": 516575,
}
}, {
"id": "rec01dTDP9T4ZtHL4",
"fields": {
"user_id": 170180717,
"user_name": "abcdefg",
"event_id": 516575,
}
}, {
"id": "unique",
"fields": {
"user_id": 1234,
"user_name": "abcdefg",
"event_id": 516575,
}
}];
const [uniqueArray, dupeArray] =
partition(
groupBy(totalArray, record => record.fields.user_id).values(),
group => group.length == 1
)
.map(groups => groups.flat(1));
console.log("uniqueArray =", uniqueArray);
console.log("dupeArray =", dupeArray);
You can use Array.reduce && Array.some like this:
let totalArray = [
{
id: "rec01dTDP9T4ZtHL4",
fields:
{
"user_id":170180717,
"user_name":"abcdefg",
"event_id":516575,
}
},
{
id:"rec01dTDP9T4ZtHL4",
fields:
{
"user_id":170180717,
"user_name":"abcdefg",
"event_id":516575,
}
},
{
id:"rec01dTDP9T4ZtHL4",
fields:
{
"user_id":1470107417,
"user_name":"abcdefg",
"event_id":516575,
}
},
{
id:"rec01dTDP9T4ZtHL4",
fields:
{
"user_id":1470107417,
"user_name":"abcdefg",
"event_id":516575,
}
},
{
id:"rec01dTDP9T4ZtHL4",
fields:
{
"user_id":14701073417,
"user_name":"abcdefg",
"event_id":516575,
}
}
];
let removeDups = totalArray.reduce((result,item,index,original)=>{
if (original.some((o,i)=>o.fields.user_id===item.fields.user_id && i!==index)) return result;
result.push(item);
return result;
},[])
console.log(removeDups);
I'm trying to create this object:
const data = [
{
"javascript": [
{
"product": "1234",
},
{
"product": "4321",
}
]
},
{
"python": [
{
"product": "9876",
}
]
}
]
Here on code snippet is the original object I'm trying to parse:
const myData = [
{
"category": "javascript",
"product": "1234"
},
{
"category": "javascript",
"product": "4321"
},
{
"category": "python",
"product": "9876"
},
];
const mountCategories = (data) => {
const categoriesObj = data.map(value => value.category).filter((value, index, a) => a.indexOf(value) === index)
const categorizedData = categoriesObj.map((value) => {
return {
value: data.map(value => {
return {
product: value.product,
}
})
}
});
return (
categorizedData
)
}
console.log(mountCategories(myData))
I'm not being able to get the category key string to work. Also I need to figure how to filter the elements properly.
You can try using array.reduce:
const myData = [
{
"category": "javascript",
"product": "1234"
},
{
"category": "javascript",
"product": "4321"
},
{
"category": "python",
"product": "9876"
},
];
let result = myData.reduce((acc,current) => {
let prev = acc.find(doc => doc[current.category]);
if(!prev){
prev = { [current.category]: [] };
acc.push(prev);
}
prev[current.category].push({product: current.product});
return acc;
}, []);
console.log(result);
I have an an array of objects. My objective is to remove objects that contain keys with empty arrays.
I am using ramda, but am hitting a wall at the moment.
const myData = {
"one": {
"two": {
"id": "1",
"three": [{
"id": "33",
"copy": [{
"id": "1",
"text": "lorem",
"answer": [],
},
{
"id": "2",
"text": "ipsum",
"answer": [{
"id": 1,
"class": "science"
}]
},
{
"id": "3",
"text": "baesun",
"answer": [{
"id": 2,
"class": "reading"
}]
}
],
}]
}
}
}
flatten(pipe(
path(['one', 'two', 'three']),
map(step => step.copy.map(text => ({
answers: text.answer.map(answer => ({
class: answer.class,
})),
}), ), ))
(myData))
This the result:
[{"answers": []}, {"answers": [{"class": "science"}]}, {"answers": [{"class": "reading"}]}]
This is the expectation:
[{"answers": [{"class": "science"}]}, {"answers": [{"class": "reading"}]}]
Get the the array of inside three with path, chain the arrays inside the copy properties, and project them to contain only answer. Reject empty answers, and then evolve the objects inside each answer to contain only the class property.
const {pipe, path, chain, prop, project, reject, propSatisfies, isEmpty, map, evolve} = ramda
const transform = pipe(
path(['one', 'two', 'three']), // get the array
chain(prop('copy')), // concat the copy to a single array
project(['answer']), // extract the answers
reject(propSatisfies(isEmpty, 'answer')), // remove empty answers
map(evolve({ answer: project(['class']) })) // convert the objects inside each answer to contain only class
)
const data = {"one":{"two":{"id":"1","three":[{"id":"33","copy":[{"id":"1","text":"lorem","answer":[]},{"id":"2","text":"ipsum","answer":[{"id":1,"class":"science"}]},{"id":"3","text":"baesun","answer":[{"id":2,"class":"reading"}]}]}]}}}
const result = transform(data)
console.log(result)
<script src="//bundle.run/ramda#0.26.1"></script>
use filter
const filter = R.filter,
flatten = R.flatten,
pipe = R.pipe,
path = R.path,
map = R.map;
const myData = {
"one": {
"two": {
"id": "1",
"three": [{
"id": "33",
"copy": [{
"id": "1",
"text": "lorem",
"answer": [],
},
{
"id": "2",
"text": "ipsum",
"answer": [{
"id": 1,
"class": "science"
}]
},
{
"id": "3",
"text": "baesun",
"answer": [{
"id": 2,
"class": "reading"
}]
}
],
}]
}
}
}
const result = filter(answersObj => answersObj.answers.length, flatten(pipe(
path(['one', 'two', 'three']),
map(step => step.copy.map(text => ({
answers: text.answer.map(answer => ({
class: answer.class,
}))
})))
)(myData)))
console.log(result);
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>
I have two arrays of objects:
1)
[
{
"userId": 9
},
{
"userId": 14
}
]
2)
[{"role": "1", "group": "3"}, {"role": "1", "group": "2"}]
I would like to merge two arrays as follows:
[
{"userId":9,"role":"1","group":"2"},
{"userId":14,"role":"1","group":"2"}
{"userId":9,"role":"1","group":"3"},
{"userId":14,"role":"1","group":"3"}
]
I tried to use let however I couldn't find the way to manipulate switch the subarray :
let arr1 = [{"userId": 9}, {"userId": 14}];
let arr2 = [{"role": "1", "group": "3"}, {"role": "1", "group": "2"}];
let result = arr1.map(o => Object.assign(o, ...arr2));
console.log(result);
return result;
The result I got with the previous implementation is like this :
[{"userId":9,"role":"1","group":"2"},{"userId":14,"role":"1","group":"2"}]
However, I would like to get the result as follows :
[
{"userId":9,"role":"1","group":"2"},
{"userId":14,"role":"1","group":"2"}
{"userId":9,"role":"1","group":"3"},
{"userId":14,"role":"1","group":"3"}
]
var a = [{
"userId": 9
},
{
"userId": 14
}
]
var b = [{
"role": "1",
"group": "3"
}, {
"role": "1",
"group": "2"
}]
console.log(
b.map(z=>a.map(x=>({...x, ...z}))).flat()
)
Another solution using for loop
let arr1 = [{ "userId": 9 }, { "userId": 14 }]
let arr2 = [{"role": "1","group": "3"}, {"role": "1","group": "2" }]
let result = [];
for (let group of arr2) {
for (let user of arr1) [
result.push(Object.assign({}, group, user))
]
}
console.log(JSON.stringify(result))
//output is:
// [
// {"role":"1","group":"3","userId":9},
// {"role":"1","group":"3","userId":14},
// {"role":"1","group":"2","userId":9},
// {"role":"1","group":"2","userId":14}
// ]
Stackblitz example
To achieve expected result, use below option of looping through two arrays
var x = [
{
"userId": 9
},
{
"userId": 14
}
]
var y = [{"role": "1", "group": "3"}, {"role": "1", "group": "2"}]
let result = []
y.forEach((v, i) =>{
x.forEach((y,i) => result.push({...v, ...y}))
})
console.log(result);
codepen - https://codepen.io/nagasai/pen/pxvzOG?editors=1010
You could iterate over the two arrays like this and push the merged values into result:
arr1.forEach(e => {
arr2.forEach(e2 => {
result.push(Object.assign({}, e, e2));
});
});
Which could also be written in ONE LINE:
arr1.forEach(e => arr2.forEach(e2 => result.push(Object.assign({}, e, e2))));
const arr1 = [{
"userId": 9
},
{
"userId": 14
}
];
const arr2 = [{
"role": "1",
"group": "3"
}, {
"role": "1",
"group": "2"
}];
const result = [];
arr1.forEach(e => {
arr2.forEach(e2 => {
result.push(Object.assign({}, e, e2));
});
});
console.log(result);
You can use a mix a reduce and map to boil it down to a single array of objects.
let data = [{
"userId": 9
},
{
"userId": 14
}
]
let metaData = [{
"role": "1",
"group": "3"
}, {
"role": "1",
"group": "2"
}];
let dataReducer = data.reduce((acc, curr) => {
let metadataReducer = metaData.map((val) => {
return {
...curr,
...val
};
}, []);
return [...acc, ...metadataReducer];
}, []);
console.log(dataReducer)
Here a short approach for an arbitrary count of arrays of objects.
var array1 = [{ userId: 9 }, { userId: 14 }],
array2 = [{ role: "1", group: "3" }, { role: "1", group: "2" }],
result = [array1, array2]
.reduce((a, b) =>
a.reduce((r, v) =>
r.concat(b.map(w => Object.assign({}, v, w))), []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're basically asking for a Cartesian product of the two arrays. flatMap is a useful function here. For each element of one array, merge it with all objects from the other array, then return a flat result.
const a = [{userId: 9}, {userId: 14}];
const b = [{role: "1", group: "3"}, {role: "1", group: "2"}];
const merged = b.flatMap(ae => a.map(be => ({...be, ...ae})));
console.log(merged);