I'm working with json object literals in javascript. Starting from my original json
[{"group":"sample 1","name":"FC_TOT","value":6},
{"group":"sample 1","name":"PPC","value":88},
{"group":"sample 1","name":"PRO_OX","value":6},
{"group":"sample 1","name":"POLY_TOT","value":6}],
[{"group":"sample 2","name":"FC_TOT","value":9},
{"group":"sample 2","name":"PPC","value":8},
{"group":"sample 2","name":"PRO_OX","value":7},
{"group":"sample 2","name":"POLY_TOT","value":7}]]
I need to re-sort this based on the name and assign value to each group. The new json should look like
[
{
"group": "FC_TOT",
"sample 1": 6,
"sample 2": 9
},
{
"group": "PPC",
"sample 1": 88,
"sample 2":8
},
{
"group": "PRO_OX",
"sample 1": 6,
"sample 2": 7
},
{
"group": "POLY_TOT",
"sample 1": 6,
"sample 2": 7
}
]
where the new group is the name from the original json. Any ideas how to achieve this?
You can use reduce() to build array and inside one forEach() loop to loop objects.
var data = [[{"group":"sample 1","name":"FC_TOT","value":6},{"group":"sample 1","name":"PPC","value":88},{"group":"sample 1","name":"PRO_OX","value":6},{"group":"sample 1","name":"POLY_TOT","value":6}],[{"group":"sample 2","name":"FC_TOT","value":9},{"group":"sample 2","name":"PPC","value":8},{"group":"sample 2","name":"PRO_OX","value":7},{"group":"sample 2","name":"POLY_TOT","value":7}]]
var obj = {}
//Loop main array
var result = data.reduce(function(r, e) {
//Loop each group array to get objects
e.forEach(function(a) {
//Check if current object name exists as key in obj
if (!obj[a.name]) {
//If it doesn't create new object as its value and store it in obj
obj[a.name] = {group: a.name,[a.group]: a.value}
//push value of that object in result array of reduce or r
r.push(obj[a.name])
} else {
//If it already exists in obj then assign new property to it
Object.assign(obj[a.name], {[a.group]: a.value})
}
})
// Return accumulator or result array
return r;
}, [])
console.log(result)
Related
This question already has answers here:
Find and remove objects in an array based on a key value in JavaScript
(14 answers)
Closed 1 year ago.
I want to delete an item based on its id.
I retrieve id from the cell where I click but I don't know how to retrieve id in the array to be able to compare it to that of the click to delete only the one selected and not all of the array, I'm not sure which method to use
My item.json
[{
"id": "e3c387fd-7cf1-4d5b-9825-cef745c0ab99",
"name": "item 1",
"fans": {},
"cell": [{
"id": "e2021621-9c74-4960-bf47-f6ad917ee40b",
"name": "cell 1 item 1",
},
{
"id": "d5129940-716c-47a3-81b5-f2c90e69b602",
"name": "cell 2 item 1",
}
]
},
{
"id": "79fe939b-4c64-4b73-bebd-6563f445920c",
"name": "item 2",
"fans": {},
"cell": [{
"id": "7b6b57c6-7b72-4a14-8932-51fc2e5f9b75",
"name": "cell 1 item 2",
},
{
"id": "b579f94f-605e-4c7a-a8c5-3aad9bfec9e2",
"name": "cell 2 item 2",
}
]
}
]
My function
trashItem(id) {
this.cellsListsData = this.cellsListsData.filter(cell => {
cell.id === id, console.log(cell.id, id);
});
}
this.cellsListsData = this.cellsListsData.filter(function(element) {
return element.id !== id;
});
or Just Get the index of it and then this.cellsListsData.splice(index, 1);
This would require traversing through the whole array and finding the index of object with the given id. Once you find the id, you can simply splice the array from that index with offset 1.
Below is a quick snippet for doing that.
var index_to_delete;
data.forEach(function(value, index) {
if (value.id == id_of_clicked_element) {
index_to_delete = index;
};
});
data.splice(index_to_delete, 1);
Note: Using filter will create a new array. So, if you are referencing the data array in some other variables, they will not get the new array. So, I recommend using the filter solution with caution. Also, some answers say to delete element at that index. This would remove that index from array and your array will be rendered inconsistent.
I am trying to filter a JavaScript array (JSON array) with the string array, and set it back in itself.
I am using this code (Removed JSON.stringiFy from allRecords,it was just to show the records on console)
var statusFilters = component.get("v.statusFilters");
console.log('statusFilters--->'+statusFilters);
var allRecords = component.get("v.empWrapperList");
console.log('allRecords--->'+allRecords);
var filteredRecords = allRecords.filter(rec => rec.Status__c == statusFilters);
console.log(filteredRecords);
component.set("v.empWrapperList",filteredRecords);`
Here statusFilter is a string array and allRecords is an object array.
Here are the logs from console.
statusFilters--->Paid
ClaimsDemo.js:119 allRecords--->
[
{
"Id": "a1V2x000001K29pEAC",
"Name": "CL-0000004",
"Member__c": "0032x000004bgAkAAI",
"Date_of_Service__c": "2020-06-25",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Void"
},
{
"Id": "a1V2x000001K14OEAS",
"Name": "CL-0000003",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2015-09-15",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Denied"
},
{
"Id": "a1V2x000001K14JEAS",
"Name": "CL-0000002",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2019-10-16",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Rejected"
},
{
"Id": "a1V2x000001K14EEAS",
"Name": "CL-0000001",
"Member__c": "0032x000004bgAkAAI",
"Billed__c": 22,
"Date_of_Service__c": "2020-06-04",
"Provider__c": "a112x000003VXGEAA4",
"Status__c": "Paid"
}
]
Actually it is unable to execute this line
var filteredRecords = allRecords.filter(rec => rec.Status__c == statusFilters);
Can you please help.
your first problem is stringifying.filter method is for array.
second problem is that you cant say rec.Status__c === statusFilters statusFiltersis array and Status__c is string. map to array your object array with correct key name and search rec.Status__c in this array. indexOf is a method to find in array
if statusFilters is just array which includes types like
["Void","Denied"]
then
var filteredRecords = allRecords.filter(rec => statusFilters.indexOf(rec.Status__c)>-1);
if statusFilters is an object array like
[ {"Status__c": "Void" }];
then
var filteredRecords = allRecords.filter(rec => ( statusFilters.map(x=>x.Status__c)).indexOf(rec.Status__c)>-1);
Given a JavaScript object which represents a JSON like so -
[
{
"Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828",
"Name": "Company 1",
"Locations": [
{
"Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1",
"Name": "Location 1",
"Departments": [
{
"Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e",
"Name": "Department 1",
"Employees": [
{
"Id": "92c3a085-5712-422d-8b0f-922b57889c4f",
"Name": "Employee 1",
"Title": "FrontEnd Engineer",
"Location": "New York",
"Photo": ""
}
]
}
]
}
]
}
]
I want to filter this data structure by employee name, given that there might be multiple company, location, department. Here is my attempt at it but clearly it is not working due to my understanding of how Array.filter or Array.reduce works.
filterContacts = search => {
if (search.trim() === "") {
this.setState({ filteredContacts: null, search: search });
} else {
let filteredArray = this.state.contacts.reduce((f, c) => {
let clone = [];
for (let i = 0; i < c.Locations.length; i++) {
const l = c.Locations[i];
for (let j = 0; j < l.Departments.length; j++) {
const d = l.Departments[j];
for (let k = 0; k < d.Employees.length; k++) {
const e = d.Employees[k];
if (e.Name.search(new RegExp(search, "i") > -1)) {
clone.push(l);
}
}
}
}
return clone;
}, []);
this.setState({ filteredContacts: filteredArray, search: search });
}
};
Any help would be much appreciated. Thanks.
When you use:
let clone = [];
at the top of the reduce() callback, you throw away the accumulator — the array that keeps getting passed in the loop which is being passed as f in your code. You should use the same reduce accumulator each time and push into it. At the end you'll have an array of all the values:
let arr = [{"Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828","Name": "Company 1","Locations": [{"Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1","Name": "Location 1","Departments": [{"Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e","Name": "Department 1","Employees": [{"Id": "92c3a085-5712-422d-8b0f-922b57889c4f","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]}]
let emp = arr.reduce((f, obj) => {
obj.Locations.forEach(location =>
location.Departments.forEach(department =>
f.push(...department.Employees.filter(emp => emp.Name == "Employee 1"))
)
)
return f
}, []) // <-- this array will get passed to every loop as `f`
console.log(emp)
EDIT based on comment
If you want to persevere the structure you can filter the arrays based on the length of the filtered array below them. Here's an example with some extra data see the filtering work, The first one is completely filtered the third has two employees with the same name. Basically it will preserve any item the has location that has a department that has a matching employee:
let arr = [
{"Id": "someother","Name": "Company 2","Locations": [{"Id": "loc2Id","Name": "Location 2","Departments": [{"Id": "d2","Name": "Department 2","Employees": [{"Id": "emp","Name": "Employee 2","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]},
{"Id": "8868dfdd-9b4e-4bad-a4ce-ecae6a3cc828","Name": "Company 1","Locations": [{"Id": "bd017b9c-b62e-43aa-9f00-c164a855eed1","Name": "Location 1","Departments": [{"Id": "c9e4afe3-bbdb-474f-9062-2935025bfa2e","Name": "Department 1","Employees": [{"Id": "92c3a085-5712-422d-8b0f-922b57889c4f","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}]}]}]},
{"Id": "someother","Name": "Company 2","Locations": [{"Id": "loc2Id","Name": "Location 2","Departments": [{"Id": "d2","Name": "Department 2","Employees": [{"Id": "emp","Name": "Employee 1","Title": "FrontEnd Engineer","Location": "New York","Photo": ""}, {"Id": "emp","Name": "Employee 1","Title": "FrontEnd Engineer 2","Location": "New York","Photo": ""}]}]}]},
]
let f = []
let emp = arr.filter(arr =>
arr.Locations.filter(location =>
location.Departments.filter(department => {
let emp = department.Employees.filter(emp => emp.Name == "Employee 1")
return emp.length ? emp: false
}
).length
).length
) // <-- this array will get passed to every loop as `f`
console.log(emp)
Here is another short version using map:
var rx=new RegExp(search,'i'),emp=[];
obj.map(c=>
c.Locations.map(l=>
l.Departments.map(d=>
d.Employees.map(e=>
{if(e.Name.match(rx)) emp.push(e)}
))));
search contains the case-insensitive search pattern. The result is emp, an array of employee objects.
As mentioned above, map is not really necessary and could be replaced by forEach, but in my opinion it is easier to write and does not not really cause significantly more overhead.
Edit, this time using reduce():
It’s Christmas and with too much time on my hands I’ve been playing around further. The following solution will filter out the sought employees without showing their non-matching colleagues and leaving the original array intact:
const rd=(prop,fun)=>
(a,el)=>{
var arr=el[prop].reduce(fun,[]);
if(arr.length){
var r=Object.assign({},el);
// alternatively: use spread operator
// var r={...el};
r[prop]=arr;a.push(r);}
return a;}
var rx=new RegExp('employee 1','i');
var f=ma.reduce(
rd('Locations',
rd('Departments',
rd('Employees',(a,e)=>{
if(e.Name.match(rx))
a.push(e);
return a;}
,[]),[]),[]),[]);
f will contain an array containing only those locations, departments and employees where the employees will match the regular expression rx.
rd() is a generator function returning the actual filter functions that are being used at three different reduce-levels.
The static Object.assign() function is an easy way of generating a shallow object copy (similar to the slice() method for arrays).
I have a JSON array like this:
[
{
"id": "1",
"name": "A"
},
{
"id": "2",
"name": "B"
},
{
"id": "3",
"name": "C"
},
{
"id": "4",
"name": "D"
},
....
....
{
"id": "n",
"name": "X"
}
]
I'm looking for a slice() based function that gives the last 20 item of this JSON array
function getLast(array,x){return array.slice(array.length-x)}
Just use the slice function starting with the array length minus the number of elements you want to extract.
A simple way with filters:
filteredList = list.filter((_, index) => {
return index >= list.length - 20
})
If you just need the last X items in an array I'm not sure you need filter, you can use .slice eg [1,2,3,4,5,6,7,8,9,10].slice(-5) will return [6,7,8,9,10]
One option is to use splice or slice:
// Initialize array
let arr = new Array(50).fill().map((v,i)=>i)
// Pick off last 20 elements
console.log('Last:' + arr.slice(-20))
Note: splice modifies the existing array; if you don't want to modify the existing array use slice
Another example
let arr = new Array(50).fill().map((v,i)=>i+1) // [1,2,..50]
Array.prototype.last = function(n){
return this.slice(-n)
};
console.log( arr.last(20) )
How can I replace the spaces in a JSON object's keys dynamically? For example, if I have the following object:
[{
"FIRST NAME": "Philip",
"LAST NAME": "Rivers",
"NUMBER": "17",
"GPA": "1.0",
"OLD_FACTOR": "8",
"NICENESS": "1"
}, {
"FIRST NAME": "Peyton",
"LAST NAME": "Manning",
"NUMBER": "18",
"GPA": "4.0",
"OLD_FACTOR": "5000",
"NICENESS": "5000"
}]
I want to be able to dynamically rename "FIRST NAME" and "LAST NAME" to "FIRST_NAME" and "LAST_NAME" respectively. Based on research so far, I have this function:
function replaceSpaces(data) {
debugger;
for (var i = 0; i < data.length; i++) {
var obj = data[i];
for (var key in obj) {
var replacedKey = key.split(' ').join('_');
data[i][obj] = replacedKey;
}
}
return data;
}
The "data" parameter being passed in is an object that has already had JSON.parse ran on it prior to entering this function.
My issue with this code is that it's looping through the keys just fine, and assigning the proper replaced string to "replacedKey", but it's not assigning that to the original data object.
Here's complete code using forEach.
The steps are same as Quentin has stated in his answer
Copy the value
Remove the key-value from the object
Add new item with new value in the object
var arr = [{
"FIRST NAME": "Philip",
"LAST NAME": "Rivers",
"NUMBER": "17",
"GPA": "1.0",
"OLD_FACTOR": "8",
"NICENESS": "1"
}, {
"FIRST NAME": "Peyton",
"LAST NAME": "Manning",
"NUMBER": "18",
"GPA": "4.0",
"OLD_FACTOR": "5000",
"NICENESS": "5000"
}];
// Iterate over array
arr.forEach(function(e, i) {
// Iterate over the keys of object
Object.keys(e).forEach(function(key) {
// Copy the value
var val = e[key],
newKey = key.replace(/\s+/g, '_');
// Remove key-value from object
delete arr[i][key];
// Add value with new key
arr[i][newKey] = val;
});
});
console.log(arr);
document.getElementById('result').innerHTML = JSON.stringify(arr, 0, 4);
<pre id="result"></pre>
Strictly if the JSON is get in the form of String from server:
Replace the spaces by _ from the keys.
JSON.parse(jsonString.replace(/"([\w\s]+)":/g, function (m) {
return m.replace(/\s+/g, '_');
}));
You need to:
Copy the value
Delete the old property
Modify the correct object. (data[i][obj] will convert obj to a string and try to use it as a property name).
Such:
for (var original_property in obj) {
var new_property = original_property.split(' ').join('_');
obj[new_property] = obj[original_property];
delete obj[original_property]
}
since it is JSON it is expected to come as string you could do it with a help of Regex.
var processedJson = yourJson.replace(/( +)(?=[(\w* *]*":)/g, "_");
var yourObj = JSON.parse(processedJson);
/( +)(?=[(\w* *]*":)/g will find all ocurances of within " ... ": which is a key on every JSON object.