Object to array bug - javascript

So I wrote this function to convert an object to an array.
Function:
function objectToArray(obj) {
const result = [];
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object' && value !== null) {
result[key] = objectToArray(value);
} else {
result[key] = value;
}
}
return result;
}
Object that I try to convert:
const obj = {
"1129931367": {
"id": 10,
"amount": 1,
"assets": {
"appid": 252490,
"app_name": "name",
"classid": 1129931367,
"icon_url": "url",
"tradable": 1,
"name": "name",
"market_name": "market name",
"market_hash_name": "market hash name",
"sell_listings": 3215,
"sell_price": "0.10",
"updated_at": "17-Dec-2022"
},
"market_tradable_restriction": 7,
"market_marketable_restriction": 7,
"tags": [
{
"category": "category",
"internal_name": "internal name",
"localized_category_name": "localized category name",
"localized_tag_name": "localized tag name"
},
{
"category": "category",
"internal_name": "internal name",
"localized_category_name": "localized category name",
"localized_tag_name": "localized tag name"
}
]
}
}
Output:
(1129931368) [empty × 1129931367, Array(0)]
But when I try to convert the object that I want to convert it adds a lot of empty arrays and I don't know why. Is this because there is something wrong with the Object or with my function?
Thanks for the help :D
I have tried rewriting the function I provided multiple times but this is as close as I got to what I want.

This is because you are not using the push functionality.
result[key] = value; is essentially pushing to the array in that position.
Instead you need:
function objectToArray(obj) {
const result = [];
for (const [key, value] of Object.entries(obj)) {
if (typeof value === 'object' && value !== null) {
// push a spread of the array, this avoids nesting arrays
result.push(objectToArray(value));
} else {
result.push(value);
}
}
return result;
}
const initial = {
"1129931367": {
"id": 10,
"amount": 1,
"assets": {
"appid": 252490,
"app_name": "name",
"classid": 1129931367,
"icon_url": "url",
"tradable": 1,
"name": "name",
"market_name": "market name",
"market_hash_name": "market hash name",
"sell_listings": 3215,
"sell_price": "0.10",
"updated_at": "17-Dec-2022"
},
"market_tradable_restriction": 7,
"market_marketable_restriction": 7,
"tags": [
{
"category": "category",
"internal_name": "internal name",
"localized_category_name": "localized category name",
"localized_tag_name": "localized tag name"
},
{
"category": "category",
"internal_name": "internal name",
"localized_category_name": "localized category name",
"localized_tag_name": "localized tag name"
}
]
}
}
console.log(objectToArray(initial))
EDIT: Removed the spread operator to add depth

You could take only the values and take flatMap for a flat result.
function objectToArray(object) {
return Object
.values(object)
.flatMap(value => value && typeof value === 'object'
? objectToArray(value)
: value
);
}
const obj = { "1129931367": { id: 10, amount: 1, assets: { appid: 252490, app_name: "name", classid: 1129931367, icon_url: "url", tradable: 1, name: "name", market_name: "market name", market_hash_name: "market hash name", sell_listings: 3215, sell_price: "0.10", updated_at: "17-Dec-2022" }, market_tradable_restriction: 7, market_marketable_restriction: 7, tags: [{ category: "category", internal_name: "internal name", localized_category_name: "localized category name", localized_tag_name: "localized tag name" }, { category: "category", internal_name: "internal name", localized_category_name: "localized category name", localized_tag_name: "localized tag name" }] } };
console.log(objectToArray(obj));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How to update deeply nested array of objects JavaScript

I have the following Array of object using this information I want to update array of object with value:a without mutating it directly (I am able to solve it using index but I don't want to update it using index) below is the code that I have tried so far
ccategory.map((item) =>
item.id === payload.id
? {
...item,
categoryItems: item.categoryItems.map(
(catItem) => catItem.categoryItemID === payload.categoryItemID
// stuck here how should I update categorySubItems?
),
}
: item
),
const payload={
"id": "4476c379-2c4f-4454-b59e-cae2f62fdfe2",
"categorySubItemsID": "c2cba4d6-5635-4b5c-acf3-b93b4d435aa9",
"categoryItemID": "fdb0e86b-a2d9-4029-8988-9f50121794d3",
"value": "a"
}
MyJSON looks like this
const category=[
{
"id": "4476c379-2c4f-4454-b59e-cae2f62fdfe2",
"categoryName": "Car",
"categoryFields": [
{
"name": "Car Name",
"type": "text",
"categoryID": "e9da78fb-d349-4b03-9b77-e3cc0dc57d25"
},
{
"name": "Price",
"type": "number",
"categoryID": "c9e147a6-b5d1-424b-99bf-a973ce189322"
}
],
"categoryItems": [
{
"categoryItemID": "fdb0e86b-a2d9-4029-8988-9f50121794d3",
"categorySubItems": [
{
"categorySubItemsID": "c2cba4d6-5635-4b5c-acf3-b93b4d435aa9",
"value": "",
"label": "Car Name",
"type": "text",
"categoryLinkID": "e9da78fb-d349-4b03-9b77-e3cc0dc57d25"
},
{
"categorySubItemsID": "01d5e1e7-3927-42a6-ad05-7399a5895096",
"value": "",
"label": "Price",
"type": "number",
"categoryLinkID": "c9e147a6-b5d1-424b-99bf-a973ce189322"
}
]
},
{
"categoryItemID": "f13237d7-abfd-40d3-ae35-0b59ddf5734e",
"categorySubItems": [
{
"categorySubItemsID": "2af389b9-03bc-41d3-86bb-8bf324ca3cb3",
"value": "",
"label": "Car Name",
"type": "text",
"categoryLinkID": "e9da78fb-d349-4b03-9b77-e3cc0dc57d25"
},
{
"categorySubItemsID": "934ef505-72bb-4d64-adf1-2aa5e928a539",
"value": "",
"label": "Price",
"type": "number",
"categoryLinkID": "c9e147a6-b5d1-424b-99bf-a973ce189322"
}
]
}
]
},
{
"id": "9882b210-2d99-43a3-8aea-9f7d7c88eeda",
"categoryName": "Bike",
"categoryFields": [
{
"name": "Bike Name",
"type": "text",
"categoryID": "73bee24c-ef64-4798-bc37-5fe90cbc8de7"
}
],
"categoryItems": []
}
]
In your inner .map(), if catItem.categoryItemID === payload.categoryItemID matches, you can return a new object that has an updated categorySubItems, which you can update by creating a new array by mapping catItem.categorySubItems. When mapping the sub category items, if your categorySubItemsID matches the one from the payload object, you can return a new updated object with a new value set to that of payload.value, otherwise, you can keep the original item, eg:
ccategory.map((item) =>
item.id === payload.id
? {
...item,
categoryItems: item.categoryItems.map((catItem) =>
catItem.categoryItemID === payload.categoryItemID
? {
...catItem,
categorySubItems: catItem.categorySubItems.map(subCatItem =>
subCatItem.categorySubItemsID === payload.categorySubItemsID
? {...subCatItem, value: payload.value}
: subCatItem
)
}
: catItem
),
}
: item
),
As you can see, this can get quite unwieldy. That's why it's often useful to use something like useImmer(), which allows you to directly modify a "draft" state value in an immutable way while keeping your state updates mutable.

how to split the array of object into different object on the basis of key

I have the data in this format
[{
"Consumer": [{
"Associated ID": "JSUDB2LXXX / BIC 7503 / US",
"Parent Consumer": "7503"
}],
"Owner": [{
"Entity": "EN",
"Region": "LA"
}]
}]
I want to convert in into the below format, I have to add title and value as the new key to the old key and value and have to separate each old key value in a separate object.
[{
"Consumer": [{
"title": "Associated ID",
"name": "JSUDB2LXXX / BIC 7503 / US"
},
{
"title": "Parent Consumer",
"name": "7503"
}
],
"Owner": [{
"title": "Entity",
"name": "EN"
},
{
"title": "Region",
"name": "LA"
}
]
}]
Hope it helps:
let data = [{
"Consumer": [{
"Associated ID": "JSUDB2LXXX / BIC 7503 / US",
"Parent Consumer": "7503"
}],
"Owner": [{
"Entity": "EN",
"Region": "LA"
}]
}]
let final = []
data.forEach(el => {
Object.keys(el).forEach(key => {
let values = []
Object.entries(el[key][0]).forEach(entry => {
values.push({title: entry[0], name: entry[1]})
})
let newElement = {}
newElement[key] = values
final.push(newElement)
})
})
console.log(final)
You can try it here :
https://jsbin.com/wazuyoyidi/edit?js,console
Another aproach.
const results = data.map((firstLevel) => {
const finalObject = {};
Object.entries(firstLevel).forEach(([name, array]) => {
finalObject[name] = array
.map((obj) =>
Object.entries(obj).map(([title, name]) => ({ title, name }))
)
.flat();
});
return finalObject;
});
[https://jsbin.com/rafinobexa/edit?js,console][1]

Cartesian product of javascript object with different types of values like string, object and array

I am working on an assignment.
I have the following object form.
{
name: "name here",
skills: [ "cash", "shares" ],
subjects:
[
{
subName: "subject1",
remark: ['remark1', 'remark2']
},
{
subName: "subject2",
remark: ['remark1', 'Hockey']
}
]
}
I want to generate a Cartesian product of the properties so that the output is an array of the following form:
[
{ "name": "name here", "skills": "cash", "subjects": { "subName": "subject1", “remark”: “remark2” }},
{ "name": "name here", "skills": "cash", "subjects": { "subName": "subject1", “remark”: “remark1” }},
{ "name": "name here", "skills": "cash", "subjects": { "subName": "subject2", “remark”: “remark1” }},
{ "name": "name here", "skills": "cash", "subjects": { "subName": "subject2", “remark”: “Hockey” }},
{ "name": "name here", "skills": "shares", "subjects": { "subName": "subject1", “remark”: “remark1” }},
{ "name": "name here", "skills": "shares", "subjects": { "subName": "subject1", “remark”: “remark2” }},
{ "name": "name here", "skills": "shares", "subjects": { "subName": "subject2", “remark”: “remark1” }},
{ "name": "name here", "skills": "shares", "subjects": { "subName": "subject2", “remark”: “Hockey” }}
]
I have tried many of the algorithms(mentioned in other SO posts) and even tried to customize some of them, but still not much improvement.
I would really appreciate any kind of help in this.
Thanks in advance for your help.
You could take a recursive function which separates all key/value pairs and build a new cartesian product by iterating the values, if an array with objects call getCartesian again and build new objects.
The referenced link does not work, because of the given arrays of objects which the linked answer does not respect.
function getCartesian(object) {
return Object.entries(object).reduce((r, [k, v]) => {
var temp = [];
r.forEach(s =>
(Array.isArray(v) ? v : [v]).forEach(w =>
(w && typeof w === 'object' ? getCartesian(w) : [w]).forEach(x =>
temp.push(Object.assign({}, s, { [k]: x }))
)
)
);
return temp;
}, [{}]);
}
var data = { name: "name here", skills: ["cash", "shares"], subjects: [{ subName: "subject1", remark: ['remark1', 'remark2'] }, { subName: "subject2", remark: ['remark1', 'Hockey'] }] };
console.log(getCartesian(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }

mapping JSON Data reverse?

I got stuck on a maybe simple task, but could not find any solution.
I have some JSON Data - lets say:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"]
}, {
"_id": 3,
"type": "department",
"Name": "Marketing"
}, {
"_id": 4,
"type": "department",
"Name": "Sales"
}]
As I learned here it is quite simple to get all the persons and the departments they work for together using a map array for the departments.
Then I can map the corresponding department to the Person and receive something like:
[{
"_id": 1,
"type": "person",
"Name": "Hans",
"WorksFor": ["3", "4"],
"Readable": ["Marketing", "Sales"]
}, {
"_id": 2,
"type": "person",
"Name": "Michael",
"WorksFor": ["3"],
"Readable": ["Sales"]
}]
But for another interface I need the data "the other way round" e.g.
[{
"_id": 3,
"type": "department",
"Name": "Marketing",
"employees": [
"Hans", "Michael"
]
}, {
"_id": 4,
"type": "department",
"Name": "Sales",
"employees": [
"Hans"
]
}]
Is there any decent way to achieve this structure? Two days of trying didn't get me anywhere...
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"] }, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"] }, { "_id": 3, "type": "department", "Name": "Marketing" }, { "_id": 4, "type": "department", "Name": "Sales" }];
var departments = [],
persons = [];
data.forEach(e => {
if (e.type === "person") {
persons.push(e);
} else if (e.type === "department") {
departments.push(e);
e.employees = [];
}
});
departments.forEach(d => {
var workers = persons.filter(p => p.WorksFor.indexOf(d._id.toString()) > -1)
/*.map(p => p.Name)*/ // add this if you only need the name instead of the complete "person"
d.employees = d.employees.concat(workers);
});
console.log(JSON.stringify(departments, null, 4));
You can try something like this:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}]
var ignoreDept = ['person'];
var result = data.reduce(function(p,c,i,a){
if(ignoreDept.indexOf(c.type) < 0){
c.employees = a.reduce(function(arr,emp){
if(emp.WorksFor && emp.WorksFor.indexOf(c._id.toString()) > -1){
arr.push(emp.Name)
}
return arr;
},[]);
p.push(c);
}
return p;
}, []);
console.log(result)
The solution using Array.prototype.filter() and Array.prototype.forEach() functions:
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}],
// getting separated "lists" of departments and employees(persons)
deps = data.filter(function(o){ return o.type === "department"; }),
persons = data.filter(function(o){ return o.type === "person"; });
deps.forEach(function (d) {
d['employees'] = d['employees'] || [];
persons.forEach(function (p) {
if (p.WorksFor.indexOf(String(d._id)) !== -1) { // check the `id` coincidence between the employee and the department
d['employees'].push(p.Name);
}
});
});
console.log(deps);
You could use a hash table and a single loop for each array.
Methods:
Array#reduce for iterating an array and returning the result,
Array#forEach for looping the inner array WorksFor,
Object.create(null) to generate an object without any prototypes,
some other pattern, like a closure over hash and
the use of logical OR || for checking a falsy value and taking an object as default.
hash[b] = hash[b] || { _id: b, employees: [] };
var data = [{ _id: 1, type: "person", Name: "Hans", WorksFor: [3, 4] }, { _id: 2, type: "person", Name: "Michael", WorksFor: [3] }, { _id: 3, type: "department", Name: "Marketing" }, { _id: 4, type: "department", Name: "Sales" }],
result = data.reduce(function (hash) {
return function (r, a) {
if (a.type === 'person') {
a.WorksFor.forEach(function (b) {
hash[b] = hash[b] || { _id: b, employees: [] };
hash[b].employees.push(a.Name);
});
}
if (a.type === 'department') {
hash[a._id] = hash[a._id] || { _id: b, employees: [] };
hash[a._id].type = a.type;
hash[a._id].Name = a.Name;
r.push(hash[a._id]);
}
return r;
};
}(Object.create(null)), []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Here's a way you can get the first mapping. I've added some comments so you can follow along, and with it I hope you can find the answer to your second problem.
// First, let's get just the items in this array that identify persons
// I've called this array "data"
data.filter(x => x.type === 'person')
// Now let's map over them
.map(person =>
// We want all of the data associated with this person, so let's
// use Object.assign to duplicate that data for us
Object.assign({}, person, {
// In addition, we want to map the ID of the WorksFor array to the Name
// of the corresponding department. Assuming that the _id key is unique,
// we can due this simply by mapping over the WorksFor array and finding
// those values within the original array.
Readable: person.WorksFor.map(wfId =>
// Notice here the parseInt. This will not work without it due to
// the type difference between WorksFor (string) and _id (integer)
data.find(d => d._id === parseInt(wfId)).Name
)
})
);
var data = [{ "_id": 1, "type": "person", "Name": "Hans", "WorksFor": ["3", "4"]}, { "_id": 2, "type": "person", "Name": "Michael", "WorksFor": ["3"]}, { "_id": 3, "type": "department", "Name": "Marketing"}, { "_id": 4, "type": "department", "Name": "Sales"}];
var dep = {};
data.forEach(e => (e.type === 'person' && e.WorksFor.forEach(d => dep[d]? dep[d].push(e.Name): dep[d] = [e.Name])));
data.forEach(e => (e.type == 'department' && (e.employees = dep[e._id] || [])));
data = data.filter(e => e.type == 'department');
console.log(data);

Javascript Loop and filter out the data thats null or empty

I have some data and I need to filter out the data thats null or empty and create a new data list thats filtered.
In this case sometimes "names" array is null so I need that data out.
{
"people": [
{
"id": "2",
"description": "desc here",
"names": [
{
"name": "name here",
},
{
"name": "name here",
}
],
"other": "0"
},
{
"id": "200",
"description": "desc here",
"names": null
"other": "0"
},
{
"id": "64",
"description": "desc here",
"names": [
{
"name": "name here",
},
{
"name": "name here",
}
],
"other": "1"
}
]
}
How can I do this?
You could iterate the arrays and objects recursive until a primitive is found. Then check and return the value.
function copy(object) {
var o;
if (Array.isArray(object)) {
return object.reduce(function (r, a) {
var v = copy(a);
v.names !== null && v.names !== '' && r.push(v);
return r;
}, []);
}
if (object !== null && typeof object === 'object') {
o = {};
Object.keys(object).forEach(function (k) {
o[k] = copy(object[k]);
});
return o;
}
return object;
}
var data = { people: [{ id: "2", description: "desc here", names: [{ id: "345", name: "name here", }, { id: "54", name: "name here", foo: "", }], other: "0" }, { id: "2", description: "desc here", names: null, other: "0" }, { id: "64", description: "desc here", names: [{ id: "87", name: "name here", }, { id: "53", name: "name here", }], other: "1" }] },
result = copy(data);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var newArray = oldArray.filter(function(v){return v!==''});
new_array=yourObject.people.filter(function(elem){
return elem.names!==null && elem.names!==""
});

Categories

Resources