Dynamically building object in the loop from another array - Javascript - javascript

I want to build an object dynamically from array inside another object. I have put together my code below but that code is fetching the data and building static object.
const data = {
"time": {
"bkts": [
{
"timex": "2021-03-01T00:00:00.000Z",
"bkts": [
{
"key": "abc",
"trd1": {
"value": 0.2
},
"trd2": {
"value": 1.2
}
}
]
},
{
"timex": "2021-02-01T00:00:00.000Z",
"bkts": [
{
"key": "xyz",
"trd1": {
"value": 0.2
},
"trd2": {
"value": 1.2
}
}
]
}
]
}
};
let timestamp = "";
let trd1 = "";
let trd2 = "";
let trdArray1 = [];
let trdArray2 = [];
let dataArray = [];
const responseData = data.time;
responseData.bkts.map(function (val) {
timestamp = new Date(val.timex);
val.bkts.map((sub_val) => {
trd1 = sub_val.trd1.value;
trd2 = sub_val.trd2.value;
});
trdArray1.push([timestamp,trd1]);
trdArray2.push([timestamp,trd2]);
const trd1Object = {
id: "trd1",
name: "Trd 1",
data: trdArray1
};
const trd2Object = {
id: "trd2",
name: "Trd 2",
data: trdArray2
};
const trd1ObjectArray = new Array(trd1Object);
const trd2ObjectArray = new Array(trd2Object);
dataArray = [...trd1ObjectArray,...trd2ObjectArray];
});
console.log(dataArray);
The above code works fine but I want it to be dynamic so if there are 10 numbers of items "trd" then i dont need to build my code 10 times.

I think there is many things to focus on here,
The first thing, your code contains many many syntax errors, some missing commas and closing brackets, so run anywhere and track these errors first until you reach to the error that says Uncaught TypeError: trd1Object is not iterable and then let's talk.
The first point:
You cannot spread an object inside an array, only the opposite is possible.
The second point:
You don't need to use the map() method to loop over the array, the map() method is created to return a new updated array from an existing one, and not to loop over an array to just do some actions.
You can use the forEach() method for this porpuse, and it's the same syntax.
The third point:
You have a problem in declaring variables, which is declaring multiple variables in the same line and assign a value for them all.
This just assigns the value to the last variable, and the first ones will be undefined
which means, if you have this line of code:
let x, y, z = ""
then you find that x = undefined and y = undefined and z = "" so you cannot use this syntax here, I know that it's found in some other languages but not in javascript.
The fourth point:
If you need to build a dynamic code, you must put all the variables except the parent array inside the function of the map() or the forEach() method, which means that every time the function will be called, these variables will be created newly just for this new value, and then append the final result of your function to the parent array.
I could help you with more examples of code snippets if I understood exactly what you need to do, and If the code works well.
And a small advice, when working on anything even for training, name your variables with the full meaning of it, and name everything with a descriptive names, because nobody understands what variables means here.

Related

Extracting unique values from an array of objects where value is a nested object in JavaScript

Let's say I've got the following array of objects in JavaScript:
const requests = [
{
id: 1,
person: {
id: 1
}
},
{
id: 2,
person: {
id: 1
}
},
{
id: 3,
person: {
id: 2
}
},
{
id: 4,
person: {
id: 3
}
},
{
id: 5,
person: {
id: 2
}
}
]
And what I've written below will go over each item in the array, and then create a new array containing just the person object.
const requestsPeopleIds = []
for (const request of requests) {
requestsPeopleIds.push(request.person.id)
}
I then take that new array and create another new array using Set to remove the duplicate ids:
const uniquePeopleIds = Array.from(new Set(requestsPeopleIds))
The final result is as I'd expect:
console.log(uniquePeopleIds) // [1, 2, 3]
where these are the unique ids of the people who made a request. So out of the 5 requests, these were made by 3 people.
There must be a more efficient way of doing this, so I'm reaching out to you stack overflow JS gurus.
Thanks in advance.
I think you got the basics. Here's a way to tighten the code:
var ids = new Set;
requests.forEach(i => ids.add(i.person.id));
You could also do this with map method and spread syntax ....
const requests = [{"id":1,"person":{"id":1}},{"id":2,"person":{"id":1}},{"id":3,"person":{"id":2}},{"id":4,"person":{"id":3}},{"id":5,"person":{"id":2}}]
const result = [...new Set(requests.map(({ person: { id }}) => id))]
console.log(result)
You can do it by making an object by the person's id as a key and get the keys of the object.
const requests = [{"id":1,"person":{"id":1}},{"id":2,"person":{"id":1}},{"id":3,"person":{"id":2}},{"id":4,"person":{"id":3}},{"id":5,"person":{"id":2}}]
// Take an empty object
const uniques = {};
// Iterate through the requests array and make person's id as a
// key of the object and put any value at this index (here I put 1).
requests.forEach(request => (uniques[request.person.id] = 1));
// Finally get the keys of the unique object.
console.log(Object.keys(uniques));
I've done some research and have inferred some interesting facts:
It looks like when we have very various data and larger array, then Set collection shows not best results. Set is very optimized collection, however, in my view, it should always check whether element is already added into Set. And this checking will take O(n) complexity. But we can use simple JavaScript object. Checking whether object contains key is O(1). So object will have huge advantage over Set.
foreach arrow function is very convenient, however, simple for loop is faster.
Adding console.log makes Set the most fastest solution, however, without console.log, the most fastest solution is combination of for loop and object.
So the most performant code without console.log() looks like this:
const hashMap = {};
const uniques = [];
for (let index = 0; index < requests.length; index++) {
if (!hashMap.hasOwnProperty(requests[index].person.id)){
hashMap[requests[index].person.id] = 1;
uniques.push(requests[index].person.id);
}
}
However, the most performant code with console.log() looks like this(I cannot understand the reason why it happens. It would be really great to know why it happens):
var ids = new Set;
requests.forEach(i => ids.add(i.person.id));
console.log(ids)
Tests:
with console.log
without console.log

Check and add dates key and values to existing json object only if the values doesn't exist

the main object where data is to be added
let calendarObject = {
"2017": [
"2017/01/01",
"2017/02/09"
],
"2018": [
"2018/01/01",
"2018/02/05",
"2018/05/16",
"2018/08/02",
"2018/10/08",
"2018/10/09",
"2018/10/11",
]
}
this is the array to be added to the last node of calendarObject
let dates = [
"2017/10/23",
"2017/11/14",
"2018/10/05",
"2018/10/07",
"2018/10/08",
"2018/10/09",
"2018/10/13"
]
I want to merge the array like
let calendarObject = {
"2017": [
"2017/01/01",
"2017/02/09",
"2017/10/23",
"2017/11/14"
],
"2018": [
"2018/01/01",
"2018/02/05",
"2018/05/16",
"2018/08/02",
"2018/10/08",
"2018/10/09",
"2018/10/11",
"2018/10/05",
"2018/10/07",
"2018/10/13"
]
}
Is javascript sets must or what are the possible ways to do it efficiently?
I can check the availability of element in the array loop
calendarObject[year].indexOf(dates[index]) === -1 ? NaN : NaN
i'm stuck with objects, sets and arrays or what's the best alternative to work with these type of datas?
Your code:
datesArray.forEach((date, index) =>{
let dateYear = dates.split('/')[0];
calendarObject[dateYear].push(dates);
});
should work if you change the dates references in your function body into date.
and what if dateYear was "2019" which is out of object bound the console will throw an error like "cannot read property [2019] of undefined" or sth like that
You can check the existence of the property for a year before pushing the item:
datesArray.forEach(date => {
let dateYear = date.split('/')[0];
if ( !calendarObject[dateYear] ) {
// define a object property for a non-existent year
calendarObject[dateYear] = {};
}
calendarObject[dateYear].push(date);
});
what are the other methods for improving performance?
You should consider improving performance of your code only when it noticeably slow down your application. Since you have a small array, the forEach loop should work fast enough. If you have a larger array you can replace the .forEach with a simple for loop.
datesArray.forEach((date, index) =>{
let dateYear = dates.split('/')[0];
calendarObject[dateYear].push(dates);
});
this can be one solution

Typescript foreach variable not available

I have a foreach loop where I create a new temp array, then run a nested foreach loop. I'm then trying to access the temp array inside the nested foreach loop, but it's coming back with a "variable not available" error.
let final = {
array: []
};
myArray.forEach(item =>
{
let newObject = { items: [] };
item.subArray.forEach(subItem =>
{
var subObject = { prop: subItem.prop };
// Error here: "newObject is not available"
newObject.items.push(subObject);
});
// Error here: "final is not available"
final.array.push(newObject);
});
I know I can provide this to the array by providing it as an argument (eg: item.subArray.forEach(subItem => {},this);)
but this doesn't help me because tempArray doesn't exist at the class level.
I have the same problem when I try to assign my temp array to the "final" array declared outside the foreach.
Is there a way I can access the parent scope from within the foreach?
I should point out this code exists within a function defined on a class. I'm basically trying to aggregate properties with a certain value from within the subarray
Screenshot showing the issue: http://i.imgur.com/HWCz0Ed.png
(The code visible in the image is within the first forEach loop)
Update: I figured this out, it was an issue between using let and var. See my answer below for details.
The code you pasted into the question must not be your real code. if it was you would have had no problem accessing finalArray.
The results of both your snippets are very different.
the first will give you an array of all the properties of the sub item of the last item.
the seconds will give you an array of arrays where each array contains the properties of the sub item
If I understand correctly what you want is to get a single array containing all the properties of all the sub items. so you want to map each item to an array of sub-item properties and then flatten the result into a single array.
How about this?
var items = [
{subitems:[
{prop:1},
{prop:2},
]},
{subitems:[
{prop:3},
{prop:4},
]},
]
var result = items.map(function(item){
return item.subitems.map(function(subitem){
return subitem.prop;
})
}).reduce(function(prev,curr){
return prev.concat(curr);
},[]);
console.log(result);
Update: I finally figured this out. In my actual code I was creating newObject using TypeScript's let keyword. I changed it to var instead and it started working.
Chalk that up to me not understanding the difference between let (block scope) and var (global scope) - d'oh!
The solution listed below also worked for me, but simply changing let to var has meant that my original code works perfectly.
I solved this by using map() instead of forEach():
var final = {
array: []
};
var finalArray = myArray.map(function (item)
{
let newObject = { items: [] };
var tempArray = item.subArray.map(function (subItem)
{
var subObject = { prop: subItem.prop };
return subObject;
});
newObject.items = tempArray;
return newObject;
});
final.array = finalArray;

get index of element in array if it exists in another array/object

There are two arrays:
itemKeys: [
{
name: "REFOBJTYPE"
},
{
name: "REFOBJKEY"
}
...
]
itemValues: [
{
value: ""
},
{
value: ""
}
]
and an object
ref: {
REFOBJTYPE: 1,
REFOBJKEY: 2,
}
They are fixed and the structure itself cannot be changed.
values of itemValues should be filled with values from ref object,
to get index we have to look up the itemKeys array.
The point of this question: I don't want to use 2 "for" loops to check for each key if it exists in ref. I WANT use JAVASCRIPT specific features like maybe "indexOf", so:
is the ANY OTHER way, rather than TWO FOR-LOOPs to complete this task?
Please don't question why I need this, why don't I like 2 loops. Obviously under any implementation "behind" it will be 2 loops.
I'm not sure if this is what you meant, but if you loop over the itemKeys array, you can easily look up the value associated with the key in the ref object, and then write that out to the itemValues array in one loop.
for (var i = 0; i < itemKeys.length; i++) {
var key = itemKeys[i].name;
var value = ref[key];
itemValues[i].value = value;
}

Javascript function and array problem

I am trying to pass some data to a function that uses those arguments as identifiers for a multi dimensional array, and then return the value hardcoded to that array. I am not sure what I am doing wrong, but something is breaking.
I can get an alert() to pop before I assign any array values, but it seems to die at that point. Any help is appreciated.
// Get Column A's number
var a1 = Number($('#p-a').attr("numb"));
// Get Column B's number
var b1 = Number($('#p-b').attr("numb"));
// Get status for column A
var a_status = $('#p-a').attr("status");
// Get status for column A
var b_status = $('#p-b').attr("status");
// If same, status="s" else, status="i"
var status = "";
if(a_status == b_status) { status = "s"; }else{ status = "o"; }
// Get the value of the numbers + status
var a = this_function(a1, b1, status, "2");
// Update the status div
$('#status').html(a);
function this_function(a1, a2, s, p)
{
this_array = array();
this_array['1']['1']['1']['1'] = "10";
this_array['1']['1']['1']['2'] = "20";
this_array['1']['2']['1']['1'] = "40";
this_array['1']['2']['1']['2'] = "60";
//
return this_array[a1][a2][s][p];
}
You cannot initialize arrays like that. Every level needs to be initialized individually. And as you don't have numerical keys only, I'd use an object instead:
var this_array = {
'1': {
'1': {
'o': {
'1': "10",
'2': "20"
}
},
'2': {
'o': {
'1': "40",
'2': "60"
}
}
}
};
You'd also have to define what happens if a key does not exist. E.g. currently, if status is 's' then you will get an error.
The if statement can be written shorter using the conditional operator:
var status = (a_status == b_status) ? 's' : 'o';
Update: If you really want to have a numerical array, provided the keys are numerical only, you can create the array like so:
var this_array = [
[], // this_array[0]
[ // this_array[1]
[], // this_array[1][0]
[ // this_array[1][1]
[], // this_array[1][1][0]
[null, 10, 20] // this_array[1][1][1][...]
],
[ // this_array[1][2]
[], // this_array[1][2][0]
[null, 40, 60] // this_array[1][2][1][...]
]
]
];
You see, if you do not start your indices with 0 the structure becomes quite confusing.
Your array notation within this_function is incorrect (barring your having an array function that creates the array in the form you show). Notes:
function this_function(a1, a2, s, p)
{
this_array = array(); // <== There is no `array` function in std. JavaScript
this_array['1']['1']['o']['1'] = "10"; // <== Unless you've created an object/array at this_array['1'] (which you haven't), this line will fail
this_array['1']['1']['o']['2'] = "20";
this_array['1']['2']['o']['1'] = "40";
this_array['1']['2']['o']['2'] = "60";
//
return this_array[a1][a2][s][p];
}
I'm not entirely sure what this_function should do, or I'd offer a replacement function. Some thoughts:
Creating an array, you use [] (or new Array(), but that's just a longer form of the same thing).
You have to create each object/array in an array. So you can't assign to this_array['1']['1']['o']['1'], for instance, until you've created an object/array at this_array, this_array['1'], this_array['1']['1'], and this_array['1']['1']['o'].
Your this_function function will create a new array each time it's called. That seems dramatically inefficient.
JavaScript arrays aren't really arrays, they're just objects with some special features. You may just want objects, given that not all of your keys are numeric. If you really want arrays, though, they mostly start with index 0 rather than 1.
You're quite correct that array indexes are really strings, but they're almost always written as numbers and it's totally fine to do that (leaving off the quotes). Using the quotes (which is, again, technically correct) will tend to confuse people trying to maintain the code. (But if you use objects rather than arrays, it will mostly help.)
First and foremost there is no array() function in Javascript. I don't know if it refers to some other point of your code but arrays are created via the array constructor new Array() or an array literal []
Secondly what you are using is not a real numberical indexed array.
For the assignment part: you have one array/object but the deeply nested objects/arrays are undefined.
Your code dies at: this_array['1']['1']['o']['1'] = "10"; because this_array['1'] is undefined which can't have any property so the chain is broken.
Then there is a problem with types. You convert the attribute to number by Number($('#p-a').attr("numb")); and then you use strings as indexes. This is related to the array/object confusion.
What you need is to create a real array, and use numerical indexes:
// move it outside so you only
// create this beast once
var array = [ // first level
[ // second level
[ // third level
[10, 20] // fourth level
],
[
[40, 60]
]
// , [...]
]
];
function this_function(a1, a2, s, p) {
return array[a1-1][a2-1][s-1][p-1];
}
i'm not well versed in needing to deal with multidimensional arrays, but you need to define all your inner arrays before you can set them to anything. something like this:
var this_array = [];
this_array['1'] = [];
this_array['1']['1'] = [];
this_array['1']['2'] = [];
this_array['1']['1']['o'] = [];
this_array['1']['2']['o'] = [];
this_array['1']['1']['o']['1'] = "10";
this_array['1']['1']['o']['2'] = "20";
this_array['1']['2']['o']['1'] = "40";
this_array['1']['2']['o']['2'] = "60";
i tried to console this result out and everything came up as undefined, but within the array at least and didn't die.

Categories

Resources