set array based on an array of indexes - javascript

I want to set a boolean value in a nested object structure, based on a list of indexes
The data I want to update looks like this:
let categories = [{
"name": "Cat 1",
"subs": [{
"name": "Sub Cat 1.1",
"subs": [],
"checked": false
},
{
"name": "Sub Cat 1.2",
"subs": [],
"checked": false
}
],
"checked": false
},
{
"name": "Cat 2",
"subs": [],
"checked": false
}
];
The indexes are stored in an array:
let categoryIndexs = [0,1]
So based on categoryIndexs I want to change the checked property of the object with name "Sub Cat 1.2" to true.
It is like transforming the array [0,1] to find categories[0].subs[1] and update its checked property.
So far I managed to get the value and edit it separately, but how to change the categories variable directly?
let categoryIndexs = [0,1]
let tmp_array = categories;
for(var i = 0; i < categoryIndexs.length;i++){
if(i == 0){
tmp_array = tmp_array[categoryIndexs[i]]
} else {
tmp_array = tmp_array.subs[categoryIndexs[i]]
}
}
tmp_array.checked = true
console.log(tmp_array)
The solution needs to be dynamic, so that if "Sub Cat 1.2" would have a nested entry in its own subs array, I can access it using categoryIndexs like [0,1,0]

You can iterate the given indexes in a loop and at the same time go deeper in your data structure, like in this function:
function setChecked(categories, categoryIndexes) {
let obj = null;
for (let index of categoryIndexes) {
obj = categories[index];
categories = obj.subs;
}
obj.checked = true;
}
let categories = [{"name": "Cat 1","subs": [{"name": "Sub Cat 1.1","subs": [],"checked": false},{"name": "Sub Cat 1.2","subs": [],"checked": false}],"checked": false},{"name": "Cat 2","subs": [],"checked": false}];
setChecked(categories, [0,1]);
console.log(categories);

You could use reduce to get the last subs up until the last subs and update the checked property
let categories = [{"name": "Cat 1","subs": [{"name": "Sub Cat 1.1","subs": [],"checked": false},{"name": "Sub Cat 1.2","subs": [],"checked": false}],"checked": false},{"name": "Cat 2","subs": [],"checked": false}];
let categoryIndexs = [0, 1];
function update(categories, indices) {
const last = indices.pop(); // remove the last
const redued = indices.reduce((acc, i) => acc[i].subs, categories);
redued[last].checked = true;
return categories
}
console.log(update(categories, categoryIndexs))

You could reduce the array by looking to the index of the iteration and take either subs or the item.
const
getValue = (subs, indices) => indices.reduce(
({ subs }, i) => subs[i],
{ subs }
);
let categories = [{ name: "Cat 1", subs: [{ name: "Sub Cat 1.1", subs: [], checked: false }, { name: "Sub Cat 1.2", subs: [], checked: false }], checked: false }, { name: "Cat 2", subs: [], checked: false }],
indices = [0, 1];
console.log(getValue(categories, indices, 'subs'));

Related

Convert array of objects with paths strings into nested array [duplicate]

I'm looking for the best way to convert multiple string paths to a nested object with javascript. I'm using lodash if that could help in any way.
I got the following paths:
/root/library/Folder 1
/root/library/Folder 2
/root/library/Folder 1/Document.docx
/root/library/Folder 1/Document 2.docx
/root/library/Folder 2/Document 3.docx
/root/library/Document 4.docx
and I would like to create the following array of object:
var objectArray =
[
{
"name": "root", "children": [
{
"name": "library", "children": [
{
"name": "Folder 1", "children": [
{ "name": "Document.docx", "children": [] },
{ "name": "Document 2.docx", "children": [] }
]
},
{
"name": "Folder 2", "children": [
{ "name": "Document 3.docx", "children": [] }
]
},
{
"name": "Document 4.docx", "children": []
}
]
}
]
}
];
I suggest implementing a tree insertion function whose arguments are an array of children and a path. It traverses the children according to the given path and inserts new children as necessary, avoiding duplicates:
// Insert path into directory tree structure:
function insert(children = [], [head, ...tail]) {
let child = children.find(child => child.name === head);
if (!child) children.push(child = {name: head, children: []});
if (tail.length > 0) insert(child.children, tail);
return children;
}
// Example:
let paths = [
'/root/library/Folder 1',
'/root/library/Folder 2',
'/root/library/Folder 1/Document.docx',
'/root/library/Folder 1/Document 2.docx',
'/root/library/Folder 2/Document 3.docx',
'/root/library/Document 4.docx'
];
let objectArray = paths
.map(path => path.split('/').slice(1))
.reduce((children, path) => insert(children, path), []);
console.log(objectArray);
Iterate over each string and resolve it to an object:
var glob={name:undefined,children:[]};
["/root/library/Folder 1","/root/library/Folder 2","/root/library/Folder 1/Document.docx","/root/library/Folder 1/Document 2.docx","/root/library/Folder 2/Document 3.docx","/root/library/Document 4.docx"]
.forEach(function(path){
path.split("/").slice(1).reduce(function(dir,sub){
var children;
if(children=dir.children.find(el=>el.name===sub)){
return children;
}
children={name:sub,children:[]};
dir.children.push(children);
return children;
},glob);
});
console.log(glob);
http://jsbin.com/yusopiguci/edit?console
Improved version:
var glob={name:undefined,children:[]};
var symbol="/" /* or Symbol("lookup") in modern browsers */ ;
var lookup={[symbol]:glob};
["/root/library/Folder 1","/root/library/Folder 2","/root/library/Folder 1/Document.docx","/root/library/Folder 1/Document 2.docx","/root/library/Folder 2/Document 3.docx","/root/library/Document 4.docx"]
.forEach(function(path){
path.split("/").slice(1).reduce(function(dir,sub){
if(!dir[sub]){
let subObj={name:sub,children:[]};
dir[symbol].children.push(subObj);
return dir[sub]={[symbol]:subObj};
}
return dir[sub];
},lookup);
});
console.log(glob);
It creates the same result but it is may much faster ( up to O(n) vs. O(n+n!))
http://jsbin.com/xumazinesa/edit?console

compare 2 arrays based on id as the key and create 2 more arrays out of the comparison

I have 2 arrays (array1 and array2).
I want to compare array1 and array2 by using 'id' as the key and want to create 2 resultant arrays out of array2.
First array should contain all the objects which is present in array2 but not in array1.
Second array should contain all the objects which is present in array1 and array2 both, common ones.
const array1 = [{ id: 176770 }, { id: 176771 }, { id: 176820 }];
const array2 = [
{ id: 176770, classfication: "comeone", type: "typeee" },
{ id: 176771, classfication: "comeone1", type: "typeee1" },
{ id: 176820, classfication: "comeone2", type: "typeee2" },
{ id: 176670, classfication: "comeone", type: "typeee" },
{ id: 176761, classfication: "comeone1", type: "typeee1" },
{ id: 176845, classfication: "comeone2", type: "typeee2" },
];
Please help me out to create these 2 arrays.
You can loop over the second array and find for an element with same id in first array. If there is no element present in first array, then your first condition is satisfied (Store it in result1). If the element exists in first array, your second condition is satisfied (Store it in result2)
const array1 = [{ "id": 176770 }, { "id": 176771 }, { "id": 176820 }]
const array2 = [{ "id": 176770, "classfication": "comeone", "type": "typeee" }, { "id": 176771, "classfication": "comeone1", "type": "typeee1" }, { "id": 176820, "classfication": "comeone2", "type": "typeee2" }, { "id": 176670, "classfication": "comeone", "type": "typeee" }, { "id": 176761, "classfication": "comeone1", "type": "typeee1" }, { "id": 176845, "classfication": "comeone2", "type": "typeee2" }]
let result1 = []
let result2 = [];
for (let element of array2) {
let existingInFirst = array1.find(ele => ele.id == element.id);
if (!existingInFirst) {
result1.push(element)
}
else{
result2.push(element)
}
}
console.log(result1)
console.log(result2)

Get key from object of value

I am trying to get the key from the value of the Object. I have the following array:
["Test 91", "Test 92", "Demo 1", "Demo 2"]
And I have one object:
{
D123_EMG: {
value: "Test 91",
isArchived: true
}
D21: {
value: "Test 92",
isArchived: false
}
Z6200_EMO: {
value: "Demo 1",
isArchived: true
}
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
So how can I get key as D123_EMG if the value is Test 91?
I tried this, but not getting proper response
var data = Object.keys(objectData);
var keys = []
for(var i = 0; i < array.length; i++){
for(var j = 0; j < data.length; j++){
if(array[i] === objectData[data[j].value) {
keys.push(objectData[data[j])
}
}
}
Also, can it be optimized since I used two loops or one-liner approach?
You can use filter() in this way:
const values = ["Test 91", "Test 92", "Demo 1", "Demo 2"];
const data = {
D123_EMG: {
value: "Test 91",
isArchived: true
},
D21: {
value: "Test 92",
isArchived: false
},
Z6200_EMO: {
value: "Demo 1",
isArchived: true
},
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
const keysFound = Object.keys(data).filter(key => values.includes(data[key].value));
console.log(keysFound); // ["D123_EMG", "D21", "Z6200_EMO", "G211_GTH"];
This isn't really related to react. Someone else may have a cleaner solution, but here is one that will work if I understand your question correctly:
let data = {
D123_EMG: {
value: "Test 91",
isArchived: true
},
D21: {
value: "Test 92",
isArchived: false
},
Z6200_EMO: {
value: "Demo 1",
isArchived: true
},
G211_GTH: {
value: "Demo 2",
isArchived: false
}
}
let name = '';
Object.entries(data).forEach((v) => {
// if the object value matches, set the name variable to the key
if (v[1].value == 'Test 91') {
name = v[0];
}
})
console.log(name)
I like to use .reduce() which in this case also works. Read from the MDN documentation:
The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
And you can combine it with Object.entries() where the documentation states:
The Object.entries() method returns an array of a given object's own enumerable string-keyed property [key, value] pairs, in the same order as that provided by a for...in loop. (The only important difference is that a for...in loop enumerates properties in the prototype chain as well).
See the working solution what I made:
const data = { D123_EMG: { value: "Test 91", isArchived: true }, D21: { value: "Test 92", isArchived: false }, Z6200_EMO: { value: "Demo 1", isArchived: true }, G211_GTH: { value: "Demo 2", isArchived: false } };
const filterValue = 'Test 91';
const entries = Object.entries(data);
const result = entries.reduce((a, c) => c[1].value === filterValue ? c[0] : a, '');
console.log(result);
I hope this helps!
If you're experiencing this problem in a state management store, then this is a sign that the store is not properly designed. Without more information, I can't really recommend an improvement on how to redesign your state.
So, barring a redesign of your state, you may consider creating a map by value like so:
const byValue = Object.keys(data).reduce((accumulator, currentKey) => {
const currentObject = data[currentKey];
currentObject.key = currentKey;
accumulator[currentObject.value] = currentObject;
return accumulator;
}, {});
This produces a map that looks like this:
{
"Test 91": { "value": "Test 91", "isArchived": true, "key": "D123_EMG" },
"Test 92": { "value": "Test 92", "isArchived": false, "key": "D21" },
"Demo 1": { "value": "Demo 1", "isArchived": true, "key": "Z6200_EMO" },
"Demo 2": { "value": "Demo 2", "isArchived": false, "key": "G211_GTH" }
}
With this, you use the value as the lookup key:
const test91 = byValue["Test 91"]
...

Simple JavaScript Convert JSON format

I have a json format and want to convert
Here are my script. I had tried but cannot get the correct results. Please give some advice, thanks and appreciate.
function groupBy() {
var list = [{
"id": "009",
"Nm": "Model 1",
"pid": "adidas"
},
{
"id": "007",
"Nm": "Model 1",
"pid": "adidas"
},
{
"id": "006",
"Nm": "Model 1",
"pid": "adidas"
},
{
"id": "pm1",
"Nm": "Model 1",
"pid": "puma"
},
{
"id": "003",
"Nm": "Model 1",
"pid": "adidas"
},
{
"id": "pm5",
"Nm": "Model 1",
"pid": "puma"
},
{
"id": "aj1",
"Nm": "Model 1",
"pid": "nike"
},
{
"id": "aj2",
"Nm": "Model 1",
"pid": "nike"
}
];
var output = [];
for (var i = 0; i < list.length; i++) {
if (list[i].pid != undefined) {
output.push(list[i]);
}
}
console.log(output);
}
groupBy();
One option is to reduce into an object indexed by pids, whose values are arrays. On each iteration, create the array at the appropriate property if it doesn't exist, and then push to that array:
var list = [
{"id":"009","Nm":"Model 1","pid":"adidas"},
{"id":"007","Nm":"Model 1","pid":"adidas"},
{"id":"006","Nm":"Model 1","pid":"adidas"},
{"id":"pm1","Nm":"Model 1","pid":"puma"},
{"id":"003","Nm":"Model 1","pid":"adidas"},
{"id":"pm5","Nm":"Model 1","pid":"puma"},
{"id":"aj1","Nm":"Model 1","pid":"nike"},
{"id":"aj2","Nm":"Model 1","pid":"nike"}
];
console.log(
list.reduce((a, item) => {
const { pid } = item;
if (!a[pid]) a[pid] = [];
a[pid].push(item);
return a;
}, {})
);
You're pretty close there. But [] is to initialize an array instead of an object in javascript. In JS, it's {}.
Following is one of many ways you can accomplish this.
function groupBy() {
var list = [
{"id":"009","Nm":"Model 1","pid":"adidas"},
{"id":"007","Nm":"Model 1","pid":"adidas"},
{"id":"006","Nm":"Model 1","pid":"adidas"},
{"id":"pm1","Nm":"Model 1","pid":"puma"},
{"id":"003","Nm":"Model 1","pid":"adidas"},
{"id":"pm5","Nm":"Model 1","pid":"puma"},
{"id":"aj1","Nm":"Model 1","pid":"nike"},
{"id":"aj2","Nm":"Model 1","pid":"nike"}
];
// Initialize output as an object
var output = {};
for (var i = 0; i < list.length; i++){
// 'objectKey' is where you group the list item by its 'pid'
var objectKey = list[i].pid;
// If there's a 'pid' in the list item, but 'output' is not an array yet, then..
if (objectKey && !output.hasOwnProperty(objectKey)){
// Initialize output.group to be an array
output[ objectKey ] = [];
}
// Then finally, store the list into output's group that we created above.
output[ objectKey ].push( list[i] );
}
console.log(output);
}
groupBy();
Use this method for your any group by
const groupBy = function(arr, prop) {
return arr.reduce(function(groups, item) {
const val = item[prop]
groups[val] = groups[val] || []
groups[val].push(item)
return groups
}, {})
}
const list = [
{"id":"009","Nm":"Model 1","pid":"adidas"},
{"id":"007","Nm":"Model 1","pid":"adidas"},
{"id":"006","Nm":"Model 1","pid":"adidas"},
{"id":"pm1","Nm":"Model 1","pid":"puma"},
{"id":"003","Nm":"Model 1","pid":"adidas"},
{"id":"pm5","Nm":"Model 1","pid":"puma"},
{"id":"aj1","Nm":"Model 1","pid":"nike"},
{"id":"aj2","Nm":"Model 1","pid":"nike"}
];
const groupOutput = groupBy(list, 'pid');
You pass your key as second argument into groupBy for group by.

Javascript Get the parent id from a sub id

I have some code that will return me the name of the subcat clicked.
Here is the data below:
theData = {
"categories": [
{
"id": "661",
"name": "some name",
"description": "some description",
"subcat": [
{
"id": "662",
"name": "sub 1",
"translations": null
},
{
"id": "663",
"name": "sub 2",
"translations": null
}
],
"image": null
},
{
"id": "657",
"name": "some other name",
"description": "",
"subcat": [
{
"id": "456",
"name": "sub 12",
"translations": null
},
{
"id": "656",
"name": "sub 15",
"translations": null
}
],
"image": null
}
]
};
I need some way to find the parent id of the subcat name.
For example if I gave it "sub 15", it would return "661" which is the parent id
How can I do this?
There's no way by default to access the "parent" of an object in Javascript -- it could be referenced in any number of other objects, or even by itself, so it's not possible to determine what the sole parent of an object is.
Instead, we'll just iterate through all the data until we find the matching id, and return null if we never find it. This solution counts on your IDs being unique entities, so if that's not the case, it'll have to be changed. With that said, here's an example:
function getParent(subID) {
for (var i in theData.categories) {
var parent = theData.categories[i];
if ('subcat' in parent && 'length' in parent.subcat) {
for (var j = 0; j < parent.subcat.length; j++) {
if (parent.subcat[j].id === subID) {
return parent.id;
}
}
}
}
return null;
}
If you don't like your function returning null, you can always alter it so that it returns -1, assuming that -1 is out-of-band for your IDs. Note also that this is hardly an optimal solution, so if you're intending to use this for large amounts of data, you'll want to look into faster and/or more efficient search algorithms.
try this .we have to iterate through all the data
[fiddle][1]
Fiddle
var input = "sub 15";
var id =-1;
for(var i=0;i<theData.categories.length;i++){
if(theData.categories[i].subcat!=null){
for(var j=0;j<theData.categories[i].subcat.length;j++){
if(theData.categories[i].subcat[j].name==input){
id= theData.categories[i].id;
break;
}
}
}
}
console.log(id)
You might consider more a generic solution, which searches for a given key and a value in the subcat array. Then take only the first object's id.
function getParentId(key, value) {
return (theData.categories.filter(function (a) {
return a.subcat.some(function (b) {
return b[key] === value;
});
})[0] || {}).id;
}
var theData = { categories: [{ id: 661, name: "some name", description: "some description", subcat: [{ id: 662, name: "sub 1", translations: null }, { id: 663, name: "sub 2", translations: null }], image: null }, { id: 657, name: "some other name", description: 0, subcat: [{ id: 456, name: "sub 12", translations: null }, { id: 656, name: "sub 15", translations: null }], image: null }] };
console.log(getParentId('name', 'sub 15'));
This may not be the best way but hope this will be useful
var getSubCat = []; // create an empty array to map parent id with sub name
var getCat = theData.categories; // get categories
getCat.forEach(function(item) { // loop through categories
item.subcat.forEach(function(elem) {
getSubCat.push({
id: item.id, // this is parent id
sub: elem.name // name inside each subcat object. Total 4 subcat object
});
})
})
var parentId = getSubCat.filter(function(elem){ // filter the getSubCat array
return elem.sub ==='sub 15'
})[0].id // parentId is an array, we need first object so [0]
alert(parentId)
Now I am pushing name inside each of subcat object. On requirement you can also push their id
DEMO
The below solution looks similar to furkle's solution. But here it uses jquery to iterate through the json objects.
function getParent(subID) {
var parentId = null;
$.each(theData.categories, function(i, v)
{
$.each(v.subcat, function(idx, obj){
if(obj.name ==subID)
parentId = v.id
})
})
return parentId;
}

Categories