Cartesian array based on array of objects in Javascript - javascript

I'm looking for method to find cartesian array based on array of objects.
Basicly I've seen solutions like that:
Cartesian product of multiple arrays in JavaScript
but I'm not sure how to modify it to work on object property (in my case on property "value").
For instance my input:
let arr1 = [
{
id: 1,
type: "attribute",
value: "arr1-attr1"
},
{
id: 2,
type: "attribute",
value: "arr1-attr2"
}
];
let arr2 = [
{
id: 3,
type: "attribute",
value: "arr2-attr1"
}
];
let arr3 = [
{
id: 4,
type: "attribute",
value: "arr3-attr1"
},
{
id: 5,
type: "attribute",
value: "arr3-attr2"
}
];
Expected output:
output = [
[
{
id: 1,
type: "attribute",
value: "arr1-attr1"
},
{
id: 3,
type: "attribute",
value: "arr2-attr1"
},
{
id: 4,
type: "attribute",
value: "arr3-attr1"
}
],
[
{
id: 2,
type: "attribute",
value: "arr1-attr2"
},
{
id: 3,
type: "attribute",
value: "arr2-attr1"
},
{
id: 5,
type: "attribute",
value: "arr3-attr2"
}
],
[
{
id: 1,
type: "attribute",
value: "arr1-attr1"
},
{
id: 3,
type: "attribute",
value: "arr2-attr1"
},
{
id: 4,
type: "attribute",
value: "arr3-attr1"
}
],
[
{
id: 2,
type: "attribute",
value: "arr1-attr2"
},
{
id: 3,
type: "attribute",
value: "arr2-attr1"
},
{
id: 5,
type: "attribute",
value: "arr3-attr2"
}
]
];

Just take the single arrays as items of a collection of this arrays and perform the algorithm on this data set.
var arr1 = [{ id: 1, type: "attribute", value: "arr1-attr1" }, { id: 2, type: "attribute", value: "arr1-attr2" }],
arr2 = [{ id: 3, type: "attribute", value: "arr2-attr1" }],
arr3 = [{ id: 4, type: "attribute", value: "arr3-attr1" }, { id: 5, type: "attribute", value: "arr3-attr2" }],
result = [arr1, arr2, arr3]
.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How to build a tree of objects out of a flat array of records in JavaScript?

How do I implement this properly?
const tree = buildTree(1, shuffleArray([
{ type: 'string', source_id: 1, name: 'foo', value: 'asdf' },
{ type: 'integer', source_id: 1, name: 'bar', value: 123 },
{ type: 'object', source_id: 1, name: 'nested', value: 2 },
{ type: 'object', source_id: 2, name: 'nested', value: 3, array: true },
{ type: 'boolean', source_id: 3, name: 'random', value: true },
{ type: 'string', source_id: 3, name: 'another', value: 'hello' },
{ type: 'object', source_id: 2, name: 'nested', value: 4, array: true },
{ type: 'boolean', source_id: 4, name: 'random', value: false },
{ type: 'string', source_id: 4, name: 'another', value: 'world' },
{ type: 'object', source_id: 2, name: 'nested', value: 5, array: true },
{ type: 'boolean', source_id: 5, name: 'random', value: true },
{ type: 'string', source_id: 5, name: 'another', value: 'awesome' },
]))
function buildTree(startId, array) {
const map = array.reduce((m, x) => {
m[x.source_id] = m[x.source_id] ?? {}
if (x.array) {
m[x.source_id][x.name] = m[x.source_id][x.name] ?? []
m[x.source_id][x.name].push({ id: x.value })
} else {
m[x.source_id][x.name] = x.value
}
return m
}, {})
// ??? getting lost...
}
function shuffleArray(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array
}
where the "expected tree" would be something like this:
const expectedTree = {
id: 1,
foo: 'asdf',
bar: 123,
nested: {
id: 2,
nested: [
{
id: 3,
random: true,
another: 'hello'
},
{
id: 4,
random: false,
another: 'world'
},
{
id: 5,
random: true,
another: 'awesome'
}
]
}
}
The shuffleArray is just to show that the records could be in any order, and the id (source_id) property is not necessarily in incremental order (actually in my case they are UUIDs with the hierarchy not really in any particular order). Each "record" in buildTree is a "property" record basically like this:
create table object_properties {
uuid id;
uuid source_id; // the object which has this property
string name; // the property name
uuid value; // the property value object
}
// ...and same for boolean, integer, etc. properties
create table string_properties {
uuid id;
uuid source_id; // the object which has this property
string name; // the property name
string value; // the property value string
}
In my buildTree I can kind of imagine creating a map from the source_id (the base object node which has property name), to the names, to the values. But then maybe iterating over the source IDs, looking for objects nested inside the name values, and converting them to objects instead of just IDs. But this is getting hard to comprehend and I'm sure there is an easier way somehow.
What is an algorithm to build an "object tree" from this flat list of records?
In my situation, I am fetching a bunch of deeply nested property objects, recursively, and need to stitch back together an object tree out of them.
It looks like the name "nested" plays a special role. When it occurs, the corresponding value property does not hold a literal value to assign to the named property (as is the case with other names), but is a reference to an existing source_id value.
This means your code needs to deal with that name specifically and then establish the parent-child relationship. This relationship is further influenced by the array property.
I would define buildTree as follows, making use of a Map, which is built first using its constructor argument:
function buildTree(startId, arr) {
const map = new Map(arr.map(({source_id}) => [source_id, { id: source_id }]));
for (const {source_id, name, value, array} of arr) {
if (name !== "nested") {
map.get(source_id)[name] = value;
} else if (array) {
(map.get(source_id).nested ??= []).push(map.get(value));
} else {
map.get(source_id).nested = map.get(value);
}
}
return map.get(startId);
}
// Code below has not changed
function shuffleArray(array) { for (var i = array.length - 1, j, temp; i > 0; i--) {j = Math.floor(Math.random() * (i + 1));temp = array[i];array[i] = array[j];array[j] = temp;} return array;}
const tree = buildTree(1, shuffleArray([{ type: 'string', source_id: 1, name: 'foo', value: 'asdf' },{ type: 'integer', source_id: 1, name: 'bar', value: 123 },{ type: 'object', source_id: 1, name: 'nested', value: 2 },{ type: 'object', source_id: 2, name: 'nested', value: 3, array: true },{ type: 'boolean', source_id: 3, name: 'random', value: true },{ type: 'string', source_id: 3, name: 'another', value: 'hello' },{ type: 'object', source_id: 2, name: 'nested', value: 4, array: true },{ type: 'boolean', source_id: 4, name: 'random', value: false },{ type: 'string', source_id: 4, name: 'another', value: 'world' },{ type: 'object', source_id: 2, name: 'nested', value: 5, array: true },{ type: 'boolean', source_id: 5, name: 'random', value: true },{ type: 'string', source_id: 5, name: 'another', value: 'awesome' },]))
console.log(tree);
Note that the order in which objects are pushed into arrays is defined by the original order of the objects. Since this input array is shuffled, the output may show arrays in different ordering on separate runs. Something similar holds for object keys (see Object property order)
You should try Array.prototype.group(). Please refer below document.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/group
const inventory = [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'goat', type: 'meat', quantity: 23 },
{ name: 'cherries', type: 'fruit', quantity: 5 },
{ name: 'fish', type: 'meat', quantity: 22 }
];
const result = inventory.group(({ type }) => type);
/* Result is:
{
vegetables: [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
],
fruit: [
{ name: "bananas", type: "fruit", quantity: 0 },
{ name: "cherries", type: "fruit", quantity: 5 }
],
meat: [
{ name: "goat", type: "meat", quantity: 23 },
{ name: "fish", type: "meat", quantity: 22 }
]
}
*/

Filter Array of objects with nested array

so I am trying to set up a nested filter on an array of objects.
The thing is that the filter is applied inside the object on a key that is another array of objects.
here is the code:
const items = [
{ name: "123", id: 1, value: true, arr: [{ id: 1 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 2 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 3 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 4 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 5 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 6 }] },
];
const newArray = items.filter((objects) => {
objects.arr.filter((item) => {
if (item.id === 2) {
return objects;
}
});
});
console.log(newArray);
I 'm not sure where to put the return because in this situation i just get an empty array.
You need to check the nested array contains the wanted id and return the result to the filter method.
const
items = [{ name: "123", id: 1, value: true, arr: [{ id: 1 }] }, { name: "456", id: 2, value: false, arr: [{ id: 2 }] }, { name: "456", id: 2, value: false, arr: [{ id: 3 }] }, { name: "456", id: 2, value: false, arr: [{ id: 4 }] }, { name: "456", id: 2, value: false, arr: [{ id: 5 }] }, { name: "456", id: 2, value: false, arr: [{ id: 6 }] }],
result = items.filter(({ arr }) => arr.some(({ id }) => id === 2));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use Array#some to check if current arr has an element with id equal to 2:
const items = [ { name: "123", id: 1, value: true, arr: [{ id: 1 }] }, { name: "456", id: 2, value: false, arr: [{ id: 2 }] }, { name: "456", id: 2, value: false, arr: [{ id: 3 }] }, { name: "456", id: 2, value: false, arr: [{ id: 4 }] }, { name: "456", id: 2, value: false, arr: [{ id: 5 }] }, { name: "456", id: 2, value: false, arr: [{ id: 6 }] } ];
const newArray = items.filter(({ arr = [] }) =>
arr.some(({ id }) => id === 2)
);
console.log(newArray);
As you contains only one object in arr then you can access this object by using [0] index.
Working Demo :
const items = [
{ name: "123", id: 1, value: true, arr: [{ id: 1 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 2 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 3 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 4 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 5 }] },
{ name: "456", id: 2, value: false, arr: [{ id: 6 }] },
];
const newArray = items.filter((obj) => {
if (obj.arr[0].id === 2) {
return obj;
}
});
console.log(newArray);
I answered you as per the issue you are facing but if you have multiple objects in your arr then you can go ahead with Array.some() method as suggested by other answers.

How to filter nested arrays by searching

I have an array of objects that I want to filter by comparing a nested property to a search term.
For example:
let array = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
},
{
category: 2,
label: "Checkbox1",
diId: 193909,
children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
}
]
},
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 1,
label: "Empty",
toType: "String",
value: "ebedb43f-4c53-491f-8954-d030321845cd"
},
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
},
{
category: 5,
defaultValueType: 8,
label: "Current Username",
toType: "String",
value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
},
{
category: 5,
defaultValueType: 9,
label: "Current Location",
toType: "Location",
value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
}
]
},
{
category: 4,
label: "Fixed Value",
isFixed: true,
value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
// as you can see there is no children in this object
}
]};
What I'm trying to achieve is if I search for 'nodata' for example my result should be
let array = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
}
]
}
];
Another option if I search for 'spa' my result should be
let array = [
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
}
]
}
];
I have been super confused and I decided to get some help. Thank you for your helps guys!
The following function should do the trick for you:
function searchData(dataArray, searchTerm) {
return dataArray.flatMap(obj => {
const objHasSearchTerm = Object.entries(obj)
.some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
if (objHasSearchTerm && !obj.children) return [obj];
const matchedChildren = searchData(obj.children ?? [], searchTerm);
return objHasSearchTerm || matchedChildren.length > 0
? [{
...obj,
children: matchedChildren,
}]
: [];
})
}
It recursively goes through the data array, looks for any entries that have the specified search term, and if so, places it into the newly constructed object. It will preserve the nested shape of the object, which may or may not be what is needed. Feel free to tweak the algorithm to your own needs.
let allData = [
{
category: 15,
label: "Components",
value: "a614741f-7d4b-4b33-91b7-89a0ef96a099",
children: [
{
category: 1,
label: "Carousel1",
diId: 55946,
// as you can see there are many children nested array of object
children: [{ label: "nodatafoundmessage", value: "47d18fb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "be5e027b-9163-4cfb-8816-0c8e3b816086"
},
{
category: 2,
label: "Checkbox1",
diId: 193909,
children: [{ label: "datafound", value: "47d18sb2-3e63-4542-ad0e-e5e09acb5016", children: [] }],
value: "045e8786-2165-4e1e-a839-99b1b0ceef57"
}
]
},
{
value: "4be22726-850c-4905-ab3b-039fcf607d55",
label: "Default",
children: [
{
category: 5,
defaultValueType: 1,
label: "Empty",
toType: "String",
value: "ebedb43f-4c53-491f-8954-d030321845cd"
},
{
category: 5,
defaultValueType: 2,
label: "Space",
toType: "String",
value: "2d0e1429-572b-4f21-9f83-3340bafff95a"
},
{
category: 5,
defaultValueType: 8,
label: "Current Username",
toType: "String",
value: "25f6b40a-33c7-4f17-b29d-99e8d1e4e33c"
},
{
category: 5,
defaultValueType: 9,
label: "Current Location",
toType: "Location",
value: "ed59da2f-318d-4599-9085-4d9d769a27d7"
}
]
},
{
category: 4,
label: "Fixed Value",
isFixed: true,
value: "28e90e3e-a20b-4499-9593-061a7d1e7bd6"
// as you can see there is no children in this object
}
];
function searchData(dataArray, searchTerm) {
return dataArray.flatMap(obj => {
const objHasSearchTerm = Object.entries(obj)
.some(([key, value]) => key !== 'children' && String(value).toLowerCase().includes(searchTerm.toLowerCase()));
if (objHasSearchTerm && !obj.children) return [obj];
const matchedChildren = searchData(obj.children ?? [], searchTerm);
return objHasSearchTerm || matchedChildren.length > 0
? [{
...obj,
children: matchedChildren,
}]
: [];
})
}
console.log('----- Search: nodata')
console.log(JSON.stringify(searchData(allData, 'nodata'), null, 2))
console.log('----- Search: spa')
console.log(JSON.stringify(searchData(allData, 'spa'), null, 2))

Assign new properties to an array of Objects

I have an array of Objects
const options = [
{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
I am trying to write a function that will assign new properties to the object.
The output I am looking for is:
const options = [
{ value: 1, label: "Back Pain" },
{ value: 2, label: "Body aches" },
{ value: 3, label: "Cold Sores" },
{ value: 4, label: "Cough" },
{ value: 5, label: "Constipation" },
];
I have tried to loop through the array using a for loop, but can not figure it out.
Thanks for the help:)
You can do it like this:
const data=[{ id: 1, name: "Back Pain" },
{ id: 2, name: "Body aches" },
{ id: 3, name: "Cold Sores" },
{ id: 4, name: "Cough" },
{ id: 5, name: "Constipation" },
];
var result = data.map(({id:value, name:label})=>({value, label}));
console.log(result);

Javascript transform array of object structure

I am trying to transform an array of objects structure from looking like this:
[
{
id: 1,
val: "bool",
name: "somename",
entities: [
{
id: 1,
name: "varchar",
type: "string"
}
]
},
{
id: 2,
val: "bool",
name: "somename",
entities: [
{
id: 1,
name: "varchar",
type: "string"
}
]
}
]
Into this:
[
{
id: 1,
val: "bool",
name: "somename",
entitiesName: "varchar",
entitiesType: "string"
},
{
id: 2,
val: "bool",
name: "somename",
entitiesName: "varchar",
entitiesType: "string"
}
]
So more or less I want to take two values from entities and make them into key/values in the root object instead.
I have tried using Object.entries(data).map() but I am stuck
You could use a destruction for collecting all wanted properties and build a new object.
var array = [{ id: 1, val: "bool", name: "somename", entities: [{ id: 1, name: "varchar", type: "string" }] }, { id: 2, val: "bool", name: "somename", entities: [{ id: 1, name: "varchar", type: "string" }] }],
result = array.map(
({ id, val, name, entities: [{ name: entitiesName, type: entitiesType }] }) =>
({ id, val, name, entitiesName, entitiesType })
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use Array.map()
Create two new key value pairs entitiesName and entitiesType
Delete the entities key
var data = [{
id: 1,
val: "bool",
name: "somename",
entities: [{
id: 1,
name: "varchar",
type: "string"
}]
},
{
id: 2,
val: "bool",
name: "somename",
entities: [{
id: 1,
name: "varchar",
type: "string"
}]
}
];
data = data.map(
(el) => {
el.entitiesName = el.entities[0].name;
el.entitiesType = el.entities[0].type;
delete el.entities;
return el;
}
);
console.log(data);
To avoid modification on source array.
var data = [ { id: 1, val: "bool", name: "somename", entities: [ { id: 1, name: "varchar", type: "string" } ] }, { id: 2, val: "bool", name: "somename", entities: [ { id: 1, name: "varchar", type: "string" } ] }];
var result = data.map((o) => {
var obj = {...o, 'entitiesName': o.entities[0].name, 'entitiesType': o.entities[0].type };
delete obj.entities;
return obj;
});
console.log(data);
console.log(result);
.as-console-wrapper {
max-height: 100% !important
}
You can do that by using Array.map function of array and spread operator
var data = [{
id: 1,
val: "bool",
name: "somename",
entities: [{
id: 1,
name: "varchar1",
type: "string"
}]
},
{
id: 2,
val: "bool",
name: "somename",
entities: [{
id: 1,
name: "varchar2",
type: "string"
}]
}
];
var result = data.map(
(el) => {
const { entities, ...noentities } = el;
return {...noentities, entitiesName :el.entities[0].name ,entitiesType:el.entities[0].type}
}
);
console.log(result)

Categories