// 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);
Related
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));
This question already has answers here:
How to remove all duplicates from an array of objects?
(77 answers)
Closed 4 months ago.
If the 'id' key is duplicated among the objects in the array, how to delete the object
I tried using filter, map, and set, but it doesn't work.
It's not a one-dimensional array, so I don't know how to do it.
as-is
"category": {
"key": 1,
"order": 1,
"list": [
{
"id": "12345",
...
},
{
"id": "12345",
...
},
{
"id": "67890",
...
},
]
}
to-be
"category": {
"key": 1,
"order": 1,
"list": [
{
"id": "12345",
...
},
{
"id": "67890",
...
},
]
}
We iterate over that list using reduce function, then we checked whether the key we are accessing is visited or not with keys parameter of reduce method, and if it's not visited then we just push that object to a filtered array and returning keys array to keep it updated.
const data = {
"category": {
"key": 1,
"order": 1,
"list": [{
"id": "12345"
},
{
"id": "12345"
},
{
"id": "67890"
},
]
}
}
let filtered = [];
data.category.list.reduce((keys, currentObject) => {
if (!keys.includes(currentObject.id)) { //checking if current oject id is present in keys or not
// if not present than we will just push that object in
keys.push(currentObject.id);
//getting filttered object
filtered.push(currentObject);
}
return keys; //returning keys to update it
}, [])
data.category.list = filtered; //updating list
console.log(data);
A solution based on #Nick's comment
let data ={
"category": {
"key": 1,
"order": 1,
"list": [
{
"id": "12345"
},
{
"id": "12345"
},
{
"id": "67890"
},
]
}
}
let uniq = data.category.list.filter((o,i,a) => a.findIndex(o2 => o2.id == o.id) == i)
data.category.list = uniq
console.log(data)
You can use a set to track if id
const category = [{
"category": {
"key": 1,
"order": 1,
"list": [{
"id": "12345",
},
{
"id": "12345",
},
{
"id": "67890",
},
]
}
}]
const z = category.map(elem => {
const set = new Set()
return {
...elem,
category: {
...elem.category,
list: elem.category.list.reduce((acc, curr) => {
if (!set.has(curr.id)) {
set.add(curr.id);
acc.push(curr)
}
return acc;
}, [])
}
}
});
console.log(z)
This array has the key to substitute with nested key of 'name'
const arr = ['status', 'user', ...] <-- This array contains key to be replaced with name
This is what my current response object is
[
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}
]
How do I modify the above array of objects to this below
[
{
"id": 11,
"location": "Mumbai",
"status": "NEW",
"user": "Rakesh"
}
]
can try below code
const keys = ['status', 'user']
let arr = [
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}
]
arr.map(a => keys.forEach(k => {
if(a[k] && a[k].name) a[k] = a[k].name
}));
console.log(arr);
I'd try this one:
const results = [
{
"id": 11,
"location": "Mumbai",
"status": {
"name": "NEW"
},
"user": {
"name": "Rakesh"
}
}, {
"id": 12,
"location": "Helsinki",
"status": {
"name": "NEW"
},
"user": {
"name": "Samuli"
}
}
];
const flattenObject = ([key, value]) => ((typeof value === 'object') ? {[key] : value[Object.keys(value)[0]]} : {[key]: value});
const reduceToSingleObject = (acc, b) => ({...acc, ...b});
const actualResults = results.map((result) => Object.entries(result).map(flattenObject).reduce(reduceToSingleObject));
console.log(actualResults);
Explanation:
flattenObject is a function to flatten structure of object inside object. This only takes the first prop (without knowing the name of the key). If you, for some reason, would need to flatten several key-values, then it'd need whole different kind of helper function to sort that out.
reduceToSingleObject is a function to put all the key-value pairs into a single object. This could have been done already in flattenObject function, but for the clarity, I separated it to a normal map - reduce pattern.
actualResults is the outcome where we go through all the entries of your original results.
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)
I have this object structure:
"users": {
"1": {
"id": 1,
"name": "John",
"email": "john#doe.com",
"supplier_id": 1,
"supplier_name": [
"Supplier1"
],
"supplier_code": "SUP001",
"count": "21"
}
}
I'd like to change it so it appears like this:
"users": {
"1": {
"id": 1,
"name": "John",
"email": "john#doe.com",
"suppliers":[
{
"supplier_id": 1,
"supplier_name": [
"Supplier1"
]
}
],
"supplier_code": "SUP001",
"count": "21"
}
}
I tried this hoping it would work:
const group = accumulator[item.id];
group.suppliers = [];
group.suppliers = group.suppliers.push(item.supplier_name, item.supplier_id, item.supplier_code);
return accumulator;
Unfortunately that just seems to give me a count of the objects pushed into suppliers, suppliers isn't an array and supplier_id, supplier_name and supplier_code are still visible outside of suppliers:
"users": {
"1": {
"id": 1,
"name": "John",
"email": "john#doe.com",
"supplier_id": 1,
"supplier_name": [
"Supplier1"
],
"supplier_code": "SUP001",
"count": "21",
"suppliers: 3
}
}
How do I change it to the format I want?
You could use es6 Destructuring assignment, Object.values es2017 (or Object.keys instead).
If you assume that users contains more then one user you could use reduce.
In the example below original object won't be mutated.
Hope it helps
const original = {
"users": {
"1": {
"id": 1,
"name": "John",
"email": "john#doe.com",
"supplier_id": 1,
"supplier_name": [
"Supplier1"
],
"supplier_code": "SUP001",
"count": "21"
}
}
};
const { users } = original;
const reshaped = Object.values(users).reduce((acc, { id, supplier_id, supplier_name, ...rest }) => {
acc[id] = {
...rest,
suppliers: [{
supplier_id,
supplier_name: [supplier_name]
}]
};
return acc;
}, {});
console.log(reshaped);
You need to use an object to push into the suppliers array. Also, delete the old keys which are not needed.
Edit - You can directly create an array of 1 object. Thanks #Adam
const group = accumulator[item.id];
group.suppliers = [{
supplier_id: item.supplier_id,
supplier_name: item.supplier_name,
supplier_code: item.supplier_code
}];
delete group.supplier_id;
delete group.supplier_name;
delete group.supplier_code;
return accumulator;
Here's a quick and modern solution:
const parseUsers = (users) => {
let parsedUsers = {};
for (key in users) {
const user = users[key];
// destructuring (or extracting) the relevant keys from the . user object, keeping everything else under 'rest'
const { supplier_id, supplier_name, ...rest } = user;
parsedUsers[key] = {
...rest, // spreading back our rest params
suppliers: [ // creating a new array and populating it with the keys which we previously extracted (along with their corresponding values)
supplier_id,
supplier_name
]
}
}
return parsedUsers;
}
usage: parseUsers(json.users)