Simpler way to retrieve multiple values from array - javascript

A simpler way to loop through response.Body array and retrieve values of specific elements Id and DataFields.Value - to be used in console log
RESPONSE BODY - this is what is returned when request sent in Postman
[
{
"Id": "ae61098c-eb7c-4ee8-aca7-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH127"
}
],
},
{
"Id": "84cd9a9f-d085-4642-b484-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH128"
}
],
},
{
"Id": "6629d92b-1dcf-4fc1-a019-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH129"
}
],
},
{
"Id": "47442b4f-f691-4213-b705-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH130"
}
],
}
]
MY CODE - JavaScript in Tests tab
var logReportDataQryResults = JSON.parse(responseBody);
var locationOne = 0;
var locationTwo = 1;
var locationThree = 2;
var boreholeOne = logReportDataQryResults[locationOne].Id;
const objOne = logReportDataQryResults[locationOne].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeOne = objOne ? objOne.Value : 'Not Found';
var boreholeTwo = logReportDataQryResults[locationTwo].Id;
const objTwo = logReportDataQryResults[locationTwo].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeTwo = objTwo ? objTwo.Value : 'Not Found';
var boreholeThree = logReportDataQryResults[locationThree].Id;
const objThree = logReportDataQryResults[locationThree].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeThree = objThree ? objThree.Value : 'Not Found';
I want to make code more efficient and readable

You are always using the same pattern (changing parts written in ALL_UPPERCASE):
var boreholeOne = logReportDataQryResults[ LOCATION ].Id;
const objOne = logReportDataQryResults[ LOCATION ].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeOne = objOne ? objOne.Value : 'Not Found';
You can encapsulate it in a function and pass the changing parts into it:
const getBoreholeValue = (locationId, data) => {
const id = data[locationId].Id;
const obj = data[locationId].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
return obj ? obj.Value : 'Not Found';
}
And then use it like this:
const res1 = getBoreholeValue(0, logReportDataQryResults);
const res2 = getBoreholeValue(1, logReportDataQryResults);
const res3 = getBoreholeValue(2, logReportDataQryResults);
Example:
const respBody = [
{
"Id": "ae61098c-eb7c-4ee8-aca7-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH127"
}
],
},
{
"Id": "84cd9a9f-d085-4642-b484-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH128"
}
],
},
{
"Id": "6629d92b-1dcf-4fc1-a019-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH129"
}
],
},
{
"Id": "47442b4f-f691-4213-b705-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH130"
}
],
}
]
const getBoreholeValue = (locationId, data) => {
const id = data[locationId].Id;
const obj = data[locationId].DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
return obj ? obj.Value : 'Not Found';
}
console.log(getBoreholeValue(0, respBody));
console.log(getBoreholeValue(1, respBody));
console.log(getBoreholeValue(2, respBody));

You might use a single object instead of lots of separate variables - use .map to iterate over the locations and construct a new array with the info you need:
const logReportDataQryResults = [
{
"Id": "ae61098c-eb7c-4ee8-aca7-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH127"
}
],
},
{
"Id": "84cd9a9f-d085-4642-b484-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH128"
}
],
},
{
"Id": "6629d92b-1dcf-4fc1-a019-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH129"
}
],
},
{
"Id": "47442b4f-f691-4213-b705-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH130"
}
],
}
]
const locations = [0, 1, 2];
const boreholes = locations.map((location) => {
const { Id, DataFields } = logReportDataQryResults[location];
const obj = DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeValue = obj ? obj.Value : 'Not Found';
return { Id, obj, holeValue };
});
console.log(boreholes);

var logReportDataQryResults =
[
{
"Id": "ae61098c-eb7c-4ee8-aca7-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH127"
}
],
},
{
"Id": "84cd9a9f-d085-4642-b484-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH128"
}
],
},
{
"Id": "6629d92b-1dcf-4fc1-a019-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH129"
}
],
},
{
"Id": "47442b4f-f691-4213-b705-aa080112d656",
"DataFields": [
{
"Header": "LocationDetails.LocationID",
"Value": "BH130"
}
],
}
]
const boreholes=[];
for (key in logReportDataQryResults) {
const { Id, DataFields } = logReportDataQryResults[key];
const obj = DataFields.find(({ Header }) => Header == 'LocationDetails.LocationID');
const holeValue = obj ? obj.Value : 'Not Found';
boreholes.push({ "Id": Id,"holeValue": holeValue });
}
console.log(boreholes)

Related

Nested for loop through json object array does not work

I need to build a new array based on json array (Context) bellow. Unfortunately I never reach the outer Loop after passing by first run. Is there any mistake in code? How can I solve this issue?
Thank you for help.
Context:
"rfqBp": [
{
"rfqBpId": 1041650,
"Contact": [
{
"ID": 1000014,
"SelectedContact": true
},
{
"ID": 1002411,
"SelectedContact": true
},
{
"ID": 1016727,
"SelectedContact": true
},
{
"ID": 1017452,
"SelectedContact": true
}
],
},
{
"rfqBpId": 1052326,
"Contact": [
{
"ID": 1016236,
"SelectedContact": true
},
{
"ID": 1019563,
"SelectedContact": true
}
],
},
{
"rfqBpId": 1056632,
"Contact": [
{
"ID": -1,
"SelectedContact": false
}
],
},
{
"rfqBpId": 1056637,
"Contact": [
{
"ID": 1019875,
"SelectedContact": true
}
],
}
],
script:
$scope.SelectedContacts = function() { //function starts by click on checkbox in html
let selectedContactList = [];
let finalList = [];
$scope.Context.Output = [];
for (let i = 0; i <= $scope.Context.rfqBp.length; i++) {
for (let j = 0; j <= $scope.Context.rfqBp[i].Contact.length; j++) {
if ($scope.Context.rfqBp[i].Contact[j].SelectedContact === true) {
selectedContactList = {
"ID": $scope.Context.rfqBp[i].Contact[j].ID
};
finalList.push(selectedContactList);
} else if ($scope.Context.rfqBp[i].Contact[j].SelectedContact !== true) {
continue;
}
$scope.Context.Output = finalList; //Output works but just for rfqBp[1]
};
};
$scope.Context.Output = finalList; //this part never reached
};
Output:
"Output": [
{
"ID": 1000014
},
{
"ID": 1016727
},
{
"ID": 1017452
}
]
I try to get following:
"Output": [
{
"ID": 1000014
},
{
"ID": 1016727
},
{
"ID": 1017452
},
{
"ID": 1016236
},
{
"ID": 1019563
},
{
"ID": 1019875
}
]
You can use Array.prototype.flatMap() combined with Array.prototype.filter(), Array.prototype.map() and Destructuring assignment:
const rfqBp = [{rfqBpId: 1041650,Contact: [{ID: 1000014,SelectedContact: true,},{ID: 1002411,SelectedContact: true,},{ID: 1016727,SelectedContact: true,},{ID: 1017452,SelectedContact: true,},],},{rfqBpId: 1052326,Contact: [{ID: 1016236,SelectedContact: true,},{ID: 1019563,SelectedContact: true,},],},{rfqBpId: 1056632,Contact: [{ID: -1,SelectedContact: false,},],},{rfqBpId: 1056637,Contact: [{ID: 1019875,SelectedContact: true,},],},]
const result = rfqBp
.flatMap(({ Contact }) => Contact
.filter(({ ID }) => ID > 0) // Filter to exclude negative `ID`s
.map(({ ID }) => ({ ID }))
)
console.log(result)

Put JSON data inside another object of the same JSON

I need to put the images that are on "included" into "data:{relationships: { field_imagen: { data" but the problem is that i just managed to put only the first image into every index using map and find
noticiasImages.forEach(function(data: { relationships: { field_imagen: {data: {id:any}}}} ) {
var nestedArray = noticiasData.map((noticiasImages: { id: any; }) => noticiasImages == noticiasData);
data = nestedArray && noticiasImages || noticiasData;
});
And this is my json (example node)
{
"data": [
"relationships": {
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
}
],
}
]
},
this is the included object, who is in the same level as data
"included": [
"attributes": {
"drupal_internal__fid": 8798,
"langcode": "es",
"filename": "_DSC6472 - copia.jpg",
"uri": {
"value": "public:\/\/2019-11\/_DSC6472 - copia.jpg",
"url": "\/sites\/default\/files\/2019-11\/_DSC6472%20-%20copia.jpg"
},
},
,
Expected Result:
"data": [
"relationships": {
"type": "node--actualidad_institucional",
"id": "71514647-af49-4136-8a28-9563d133070a",
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
"uri": {
"value": "public:\/\/2019-11\/_DSC6472 - copia.jpg",
"url": "\/sites\/default\/files\/2019-11\/_DSC6472%20-%20copia.jpg"
},
}
}
},
I put the uri from included into field_imagen. Tried to resolve like that, but it just put only the first image of the Array from the included object in every node:
showNoticias() {
this.frontService.getNoticias()
.subscribe((data: Noticias) => {
this.noticiasImages = Array.from(data.included);
this.noticiasData = Array.from(data.data);
let noticiasImages = this.noticiasImages.map((data: {id: any}) => data.id);
let noticiasData = this.noticiasData.map((data:{relationships: { field_imagen: { data: { id: any; }}}}) => data.relationships.field_imagen.data.id);
noticiasImages.forEach(function(data: { relationships: { field_imagen: {data: {id:any}}}} ) {
var nestedArray = noticiasData.map((noticiasImages: { id: any; }) => noticiasImages == noticiasData);
data = nestedArray && noticiasImages || noticiasData;
});
console.log(data);
});
}
Hope you can help me, thanks!
UPDATE: tried that but didnt work like expected
let merged = data.data.map((data:{relationships: { field_imagen: { data: any }}}) => Object.assign({}, noticiasImages));
console.log(data)
console.log(merged)
Sometimes using regular for loops are a better option. Using map with objects that have that many properties can get confusing. And using forEach will not give you access to the i index of the iteration in the loop, which makes things easier in this case.
for (let i = 0; i < obj.included.length; i++) {
let uri = obj.included[i].attributes.uri;
obj.data[i].relationships.field_imagen.data[0] = {
...obj.data[i].relationships.field_imagen.data[0],
...uri
}
}
console.log(obj)
Output:
{
"data": [
{
"relationships": {
"field_imagen": {
"data": [
{
"type": "file--file",
"id": "dba917f0-b80f-45ed-a569-69f2ba2b482d",
"value": "public://2019-11/_DSC6472 - copia.jpg",
"url": "/sites/default/files/2019-11/_DSC6472%20-%20copia.jpg"
}
]
}
}
}
],
"included": [
{
"attributes": {
"drupal_internal__fid": 8798,
"langcode": "es",
"filename": "_DSC6472 - copia.jpg",
"uri": {
"value": "public://2019-11/_DSC6472 - copia.jpg",
"url": "/sites/default/files/2019-11/_DSC6472%20-%20copia.jpg"
}
}
}
]
}

How to parse a JSON (Google Analytics API 4)

I have an API response in form of JSON.
"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]}}]}
I need to get each metric (metricHeaderEntries) with its values in a separate Object, which is therefore is in an array "dataTracesAll".
//Example of the construction
//dataTracesAll is an array, containing objects with key "trace" + int
dataTracesAll['trace' + (i+1)] = {
name: metricsTitles[i].name, //metric title "sessions"
x: dimensions, //list of dimensions ["20210623", "20210624"]
y: dataClear //list of metrics for each metrics is separate ["13", "18"]
}
//The full code:
var titles = [];
var dataTracesAll = [];
//raw data
for (var i=0; i < data.reports.length; i++) {
//get titles
var metricsTitles = data.reports[i].columnHeader.metricHeader.metricHeaderEntries;
metricsTitles.forEach(function(title) {
titles.push(title.name.split("ga:")[1]);
});
//values and dates raw
var dimensions = [];
var dataClear = [];
var values = data.reports[i].data.rows;
//get dates and values
values.forEach(function(val) {
dimensions.push(val.dimensions[0]);
dataClear.push(val.metrics[0].values[0]); //only the first array value is added
});
//clear values
console.log(values);
//constuct array with values
dataTracesAll['trace' + (i+1)] = {
name: metricsTitles[i].name,
x: dimensions,
y: dataClear
}
}
Result of the code:
The problem is that it adds only the first value of the metrics value array and I cannot get how to parse everything, so there is actually 2 traces.
My ideal result is:
dataTracesAll = [
trace1: {
name: "ga:sessions",
x: ['20210623', '20210624']
y: ['13', '18']
},
trace2: {
name: "ga:users",
x: ['20210623', '20210624']
y: ['13', '16']
}
];
Try this:
var data = {"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]}}]};
var titles = [];
var dataTracesAll = [];
var length = data.reports[0].data.rows[0].metrics[0].values.length;
//raw data
for (var i=0; i < length; i++) {
//get titles
var metricsTitles = data.reports[0].columnHeader.metricHeader.metricHeaderEntries;
metricsTitles.forEach(function(title) {
titles.push(title.name.split("ga:")[1]);
});
//values and dates raw
var dimensions = [];
var dataClear = [];
var values = data.reports[0].data.rows;
//get dates and values
values.forEach(function(val) {
dimensions.push(val.dimensions[0]);
dataClear.push(val.metrics[0].values[i]);
});
//constuct array with values
dataTracesAll.push({});
dataTracesAll[i]['trace' + (i+1)] = {
name: metricsTitles[i].name,
x: dimensions,
y: dataClear
}
}
console.log(dataTracesAll);
Edit: The result was supposed to be an array, so I changed the code accordingly.
I have updated you logic to make it fit for your requirement. Hope this will work.
const data =
{
"reports": [
{
"columnHeader": {
"dimensions": [
"ga:date"
],
"metricHeader": {
"metricHeaderEntries": [
{
"name": "ga:sessions",
"type": "INTEGER"
},
{
"name": "ga:users",
"type": "INTEGER"
}
]
}
},
"data": {
"rows": [
{
"dimensions": [
"20210623"
],
"metrics": [
{
"values": [
"13",
"13"
]
}
]
},
{
"dimensions": [
"20210624"
],
"metrics": [
{
"values": [
"18",
"16"
]
}
]
}
]
}
}]
}
const dataTracesAll = {};
const report = data.reports[0];
for (var i = 0; i < report.data.rows.length; i++) {
dataTracesAll[`trace${i + 1}`] = {
name: report.columnHeader.metricHeader.metricHeaderEntries[i].name,
x: [],
y: [],
}
}
Object.keys(dataTracesAll).forEach((key, index) => {
for (var i = 0; i < report.data.rows.length; i++) {
dataTracesAll[key].x.push(report.data.rows[i].dimensions[0]);
dataTracesAll[key].y.push(report.data.rows[i].metrics[0].values[index]);
}
})
console.log(dataTracesAll);

Append a key value pair by copying the value of a specific key in javascript in nested json structure

I have a nested json structure like below
const data = {
"name": "A",
"invalid": {
"distinctCountOnColumns": [
{
"key": "some_key",
"value": 101557856
}
],
"groupByAndCountOnColumns": [
[
{
"key": "some_key",
"value": "no data",
"count": 101557856
}
],
]
},
"children": [
{
"name": "B",
"count": 1654164,
"children": [
{
"name": "B1",
"count": 16564,
},
{
"name": "B2",
"count": 165411,
}
]
},
{
"name": "C",
"count": 15135
}
]
}
I want to append a key called value next to the key count by copying the value of the key count. But the key count inside the object invalid should not be considered.
The resultant data is given below
const resultData = {
"name": "A",
"invalid": {
"distinctCountOnColumns": [
{
"key": "some_key",
"count": 192869,
"value": 101557856
}
],
"groupByAndCountOnColumns": [
[
{
"key": "some_key",
"value": "no data",
"count": 101557856
}
],
]
},
"children": [
{
"name": "B",
"count": 1654164,
"value": 1654164,
"children": [
{
"name": "B1",
"count": 16564,
"value": 16564
},
{
"name": "B2",
"count": 165411,
"value": 165411
}
]
},
{
"name": "C",
"count": 15135,
"value": 15135
}
]
}
I tried this method but the key value is not getting added next to the key count.
const deepCopy = (arr) => {
let copy = [];
arr.forEach(elem => {
if(Array.isArray(elem)){
copy.push(deepCopy(elem))
}else{
if (typeof elem === 'object') {
copy.push(deepCopyObject(elem))
} else {
copy.push(elem)
}
}
})
return copy;
};
const deepCopyObject = (obj) => {
let tempObj = {};
for (let [key, value] of Object.entries(obj)) {
if(key !== "invalid" && key === "count"){
obj.value = obj[key];
}
if (Array.isArray(value)) {
tempObj[key] = deepCopy(value);
} else {
if (typeof value === 'object') {
tempObj[key] = deepCopyObject(value);
} else {
tempObj[key] = value
}
}
}
return tempObj;
};
const resultData = deepCopyObject(data);
console.log("result", data)
You could create recursive function that takes data and old and new key do be added. It also checks if the some of the parent elements has the invalid key value at it ignores that object and its children.
const data = {"name":"A","invalid":{"distinctCountOnColumns":[{"key":"some_key","value":101557856}],"groupByAndCountOnColumns":[[{"key":"some_key","value":"no data","count":101557856}]]},"children":[{"name":"B","count":1654164,"children":[{"name":"B1","count":16564},{"name":"B2","count":165411}]},{"name":"C","count":15135}]}
function update(data, oldKey, newKey, isValid = true) {
if (oldKey in data && isValid) {
data[newKey] = data[oldKey]
}
for (let i in data) {
if (isValid) {
if (typeof data[i] == 'object') {
update(data[i], oldKey, newKey, isValid && i !== 'invalid')
}
}
}
}
update(data, 'count', 'value')
console.log(data)

Javascript merge array of objects based on incrementing key

This is what I have: I want to merge object which key begins with "path-"+i . And to strip "path-i" from keys in end result.
var arr = [
{
"key": "path-0-mp4",
"value": [
"media/video/01.mp4",
"media/video/01_hd.mp4"
]
},
{
"key": "path-0-quality",
"value": [
"720p",
"1080p"
]
},
{
"key": "path-1-mp4",
"value": [
"media/video/02.mp4",
"media/video/02_hd.mp4"
]
},
{
"key": "path-1-quality",
"value": [
"SD",
"HD"
]
}
]
This is a desired result:
var arr = [
[
{
"mp4": "media/video/01.mp4",
"quality": "720p"
},
{
"mp4": "media/video/01_hd.mp4",
"quality": "1080p"
},
],
[
{
"mp4": "media/video/02.mp4",
"quality": "SD"
},
{
"mp4": "media/video/02_hd.mp4",
"quality": "HD"
},
],
]
I started doing something but its not even close:
var key, new_key, value,j=0, z=0, parr = [], obj;
for(var i = 0;i<a.length;i++){
console.log('item:' ,a[i])
key = a[i].key, value = a[i].value
if(key.indexOf('path-'+j.toString()) > -1){
new_key = key.substr(key.lastIndexOf('-')+1)
console.log(key, new_key, value)
for(var z = 0;z<value.length;z++){
parr.push({[new_key]: value[z] })
}
}
}
console.log(parr)
[
{
"mp4": "media/video/01.mp4"
},
{
"mp4": "media/video/01_hd.mp4"
},
{
"quality": "720p"
},
{
"quality": "1080p"
}
]
edit:
Array could petencially hols different keys that would need grouping in the same way, for example:
var arr = [
{
"key": "path-0-mp4",
"value": [
"media/video/01.mp4",
"media/video/01_hd.mp4"
]
},
{
"key": "path-0-quality",
"value": [
"720p",
"1080p"
]
},
{
"key": "path-1-mp4",
"value": [
"media/video/02.mp4",
"media/video/02_hd.mp4"
]
},
{
"key": "path-1-quality",
"value": [
"SD",
"HD"
]
},
{
"key": "subtitle-0-label",
"value": [
"English",
"German",
"Spanish"
]
},
{
"key": "subtitle-0-src",
"value": [
"data/subtitles/sintel-en.vtt",
"data/subtitles/sintel-de.vtt",
"data/subtitles/sintel-es.vtt"
]
},
{
"key": "subtitle-1-label",
"value": [
"German",
"Spanish"
]
},
{
"key": "subtitle-1-src",
"value": [
"data/subtitles/tumblr-de.vtt",
"data/subtitles/tumblr-es.vtt"
]
}
]
This is a desired result (create new array for each different key):
var arr = [
[
{
"mp4": "media/video/01.mp4",
"quality": "720p"
},
{
"mp4": "media/video/01_hd.mp4",
"quality": "1080p"
},
],
[
{
"mp4": "media/video/02.mp4",
"quality": "SD"
},
{
"mp4": "media/video/02_hd.mp4",
"quality": "HD"
},
],
],
arr2 = [
[
{
"label": "English",
"src": "data/subtitles/sintel-en.vtt",
},
{
"label": "German",
"src": "data/subtitles/sintel-de.vtt"
},
{
"label": "Spanish",
"src": "data/subtitles/sintel-es.vtt"
}
],
[
{
"label": "Spanish",
"src": "data/subtitles/tumblr-es.vtt",
},
{
"label": "German",
"src": "data/subtitles/tumblr-de.vtt"
}
]
]
You could split the key property, omit the first path and take the rest as index and key. Then create a new array, if not exists and assign the values.
var data = [{ key: "path-0-mp4", value: ["media/video/01.mp4", "media/video/01_hd.mp4"] }, { key: "path-0-quality", value: ["720p", "1080p"] }, { key: "path-1-mp4", value: ["media/video/02.mp4", "media/video/02_hd.mp4"] }, { key: "path-1-quality", value: ["SD", "HD"] }],
result = data.reduce((r, { key, value }) => {
let [, i, k] = key.split('-');
r[i] = r[i] || [];
value.forEach((v, j) => (r[i][j] = r[i][j] || {})[k] = v);
return r;
}, []);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If you like to group by the first part of key, you could take an object with this group as key and assign the rest as above.
var data = [{ key: "path-0-mp4", value: ["media/video/01.mp4", "media/video/01_hd.mp4"] }, { key: "path-0-quality", value: ["720p", "1080p"] }, { key: "path-1-mp4", value: ["media/video/02.mp4", "media/video/02_hd.mp4"] }, { key: "path-1-quality", value: ["SD", "HD"] }, { key: "subtitle-0-label", value: ["English", "German", "Spanish"] }, { key: "subtitle-0-src", value: ["data/subtitles/sintel-en.vtt", "data/subtitles/sintel-de.vtt", "data/subtitles/sintel-es.vtt"] }, { key: "subtitle-1-label", value: ["German", "Spanish"] }, { key: "subtitle-1-src", value: ["data/subtitles/tumblr-de.vtt", "data/subtitles/tumblr-es.vtt"] }],
result = data.reduce((r, { key, value }) => {
let [group, i, k] = key.split('-');
if (!r[group]) r[group] = [];
if (!r[group][i]) r[group][i] = [];
value.forEach((v, j) => {
if (!r[group][i][j]) r[group][i][j] = {};
r[group][i][j][k] = v;
});
return r;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I am new to this and a beginner,
is this the correct approach?
const a = [{ "key": "path-0-mp4", "value": [ "media/video/01.mp4", "media/video/01_hd.mp4" ] }, { "key": "path-0-quality", "value": [ "720p", "1080p" ] }, { "key": "path-1-mp4", "value": [ "media/video/02.mp4", "media/video/02_hd.mp4" ] }, { "key": "path-1-quality", "value": [ "SD", "HD" ] } ];
var resp = [];
for (let i = 0; i < a.length; i++) {
var inst = a[i];
var key = inst["key"];
for (let j = 0; j < inst.value.length; j++) {
var index = key.split("-")[1];
var keyinst = key.split("-")[2];
if (!resp[index]) {
resp[index] = [];
}
if (!resp[index][j]) {
resp[index][j] = {};
}
resp[index][j][keyinst] = inst.value[j];
}
}
console.log(resp);
I find this easier to read and grasp
You can save an assignment if you use reduce
const arr = [{ "key": "path-0-mp4", "value": [ "media/video/01.mp4", "media/video/01_hd.mp4" ] }, { "key": "path-0-quality", "value": [ "720p", "1080p" ] }, { "key": "path-1-mp4", "value": [ "media/video/02.mp4", "media/video/02_hd.mp4" ] }, { "key": "path-1-quality", "value": [ "SD", "HD" ] } ];
newArr = [];
arr.filter(item => item.key.endsWith("mp4"))
.forEach(item => item.value
.forEach((val, i) => newArr.push({
"mp4": val,
"quality": arr.find(qItem => qItem.key === item.key.replace("mp4", "quality")).value[i]}
)
)
)
console.log(newArr)
Here is Nina's version in an unobfuscated version
var data = [{ key: "path-0-mp4", value: ["media/video/01.mp4", "media/video/01_hd.mp4"] }, { key: "path-0-quality", value: ["720p", "1080p"] }, { key: "path-1-mp4", value: ["media/video/02.mp4", "media/video/02_hd.mp4"] }, { key: "path-1-quality", value: ["SD", "HD"] }],
result = data.reduce((resultArray, { key, value }) => {
let [, idx, suffix] = key.split('-');
resultArray[idx] = resultArray[idx] || [];
value.forEach((val, i) => (resultArray[idx][i] = resultArray[idx][i] || {})[suffix] = val);
return resultArray;
}, []);
console.log(result);
The only odd thing I did here was using an object as a lookup table to help with the speed complexity. If you have any questions let me know.
const arr = [{ "key": "path-0-mp4", "value": [ "media/video/01.mp4", "media/video/01_hd.mp4" ] }, { "key": "path-0-quality", "value": [ "720p", "1080p" ] }, { "key": "path-1-mp4", "value": [ "media/video/02.mp4", "media/video/02_hd.mp4" ] }, { "key": "path-1-quality", "value": [ "SD", "HD" ] } ];
const result = arr.reduce((table, item) => {
// Getting "path-1" from "path-1-quality"
const pathValues = item.key.split('-');
const pathValue = pathValues[0] + '-' + pathValues[1];
// Getting "quality" from "path-1-quality"
const key = pathValues[2];
// Get Index from table if already registered paths
let tIndex = table.indexLookup[pathValue];
// If there is no registered index register one
if (tIndex === undefined) {
// reassign index to new location
tIndex = table.result.length;
// register the index
table.indexLookup[pathValue] = tIndex;
table.result.push([]);
}
// Assign values
item.value.forEach((value, i) => {
const arr = table.result[tIndex] || [];
arr[i] = arr[i] || {}
arr[i][key] = value;
table.result[tIndex] = arr;
})
return table
}, {
indexLookup : {},
result: []
}).result
console.log(result)

Categories