Object value being overwritten in forEach loop - javascript

Trying to solve this question and having another question by myself instead.
let arr = [
{"Footprint_Shape":["L-Shape","H-Shape","T-Shape"]},
{"Num_of_Floors":[1,2]}
]
let answer = [];
arr[0]["Footprint_Shape"].forEach(x => {
console.log('x: ',x) //Keeping loop on first array, print the element
let newObj = {};
newObj["Footprint_Shape"] = x;
arr[1]["Num_of_Floors"].forEach(y => {
console.log('y: ',y)
newObj["Num_of_Floors"] = y
answer.push(newObj);
})
});
console.log(answer);
Below is the chrome logging which is what I was expecting.
But when I logging the answer, below is the result instead:
For each of the iteration in arr[1]["Num_of_Floors"], clearly I printed the y value correctly and immediately construct the object and push into array but seems like value 1 has always been overwritten

You are not creating a new object on the second loop. You are just changing the value of newObj in the second loop that you created on the first loop.
You can do something like:
let arr = [{"Footprint_Shape": ["L-Shape", "H-Shape", "T-Shape"]},{"Num_of_Floors": [1, 2]}];
let answer = [];
arr[0]["Footprint_Shape"].forEach(x => {
arr[1]["Num_of_Floors"].forEach(y => {
let newObj = {}; //You have to initate the object inside to create a new object every loop.
newObj["Footprint_Shape"] = x;
newObj["Num_of_Floors"] = y
answer.push(newObj);
});
});
console.log(answer);
Or you can create the object and push at the same time:
let arr = [{"Footprint_Shape": ["L-Shape", "H-Shape", "T-Shape"]},{"Num_of_Floors": [1, 2]}];
let answer = [];
arr[0]["Footprint_Shape"].forEach(x => {
arr[1]["Num_of_Floors"].forEach(y => {
answer.push({Footprint_Shape: x, Num_of_Floors: y}); //Create and push
});
});
console.log(answer);

Here, you're always overwriting the previous value:
arr[1]["Num_of_Floors"].forEach(y => newObj["Num_of_Floors"] = y
So newObj["Num_of_Floors"] will only ever be equal to the last floor in the array after the end of the loop. It sounds like you want to make and push an object on each iteration instead:
let arr = [
{"Footprint_Shape":["L-Shape","H-Shape","T-Shape"]},
{"Num_of_Floors":[1,2]}
]
let answer = [];
arr[0]["Footprint_Shape"].forEach(Footprint_Shape => {
arr[1]["Num_of_Floors"].forEach(Num_of_Floors => {
answer.push({
Footprint_Shape,
Num_of_Floors,
});
})
});
console.log(answer);

Related

How to create an N_sized Array with the size of N(x) and fill it with the numbers in a range from 0 to 100 randomly?

Hello StackOverflowCommunity! My name is Piet.
While investigating the beloved Javascript I got a bit stuck:
I´m not sure why I get 98 empty items pushed into my Array.
On Index[0] and Index[99] I get IntegerValues as expected.
Thank you for your answers! :)
// create an Array with the size of N(x) and
// fill it with numbers in a range from 0 to 100 randomly.
createNSizedArray = (x) => {
for(let i = 0; i < x; i++) {
var arr = [];
arr[i] = arr.push(Math.round(Math.random()*100));
}
return arr;
}
console.log(createNSizedArray(100));
// output -> [ 31, <98 empty items>, 1 ];
// Why are the other 98 items in the Array empty and how to change them into integer values?
Actually I inspected the Items[1-98] to find out their values and to check if they are really empty.
But:
console.log(arr[4]) for example return "undefined" to me. So they are not really empty.
You are getting a mostly undefined array because you are defining a new variable arr at each iteration. You should move the declaration of arr outside of the loop.
Here is a quick alternative: Array(100).fill().map(_=>Math.round(Math.random()*100))
Try moving the initialization of the array before the for loop. This makes sure that you don't make a new array every time the loop runs.
It is because you are creating a new array on each iteration.
Try this:
createNSizedArray = (x) => {
var arr = [];
for (let i = 0; i < x; i++) {
arr[i] = arr.push(Math.round(Math.random() * 100));
}
return arr;
};
you could use the Array method.
const createNSizeArray = (n) => {
return Array.from({ length: n }, () => Math.round(Math.random()*100 );
};
console.log(createNSizeArray(5)) // [81, 92, 23, 54, 12]
Possible solution:
const createNSizedArray = (x) => {
// it had to be moved outside the for-loop to prevent from setting everything so far to an empty array
let arr = [];
for (let i = 0; i < x; i++) {
// here you don't need both arr.push(...) and assignment
arr[i] = Math.round(Math.random()*100);
}
return arr;
}
console.log(createNSizedArray(100));
What Array.prototype.push does:
let arr = [];
console.log(arr);
arr.push(1);
console.log(arr); // [1]
arr.push(2);
console.log(arr); // [1,2]
arr.push(3);
console.log(arr); // [1,2,3]
What you're trying to achieve, as #Vincent suggested, can easily be done with:
Array(100).fill().map(_ => Math.round(Math.random() * 100))

Find Missing levels and fill it

I have two arrays and need to fill the missing values with NA by comparing the levels present in other array. I used the arr.find to search but not sure how to proceed further.
Input:
const levels = [1,2,3,4]
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}]
Output:
out = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":2,"NAME1":"NA"},{"LEVEL":3,"NAME1":"TOM"},{"LEVEL":4,"NAME1":"NA"}]
Code:
let presentLevels = [];
for (let i = 1; i <= levels.length; i++) {
let check = arr.find(p => p['LEVEL'] === levels[i])
if (check) {
presentLevels.push(i)
}
}
console.log(presentLevels)
You can use map() the levels array. Find the object with LEVEL equal to the current element. If you find an object then just return that otherwise return a new object with LEVEL and NAME1 props
const levels = [1,2,3,4]
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}]
const res = levels.map(x => (arr.find(a => a.LEVEL === x) || {level: x, NAME1: "NA"}));
console.log(res)
Using Array.find() inside a loop might cause a performance issue if the arr is large enough. I would create a Map of existing levels by LEVEL, and then use the Map to get the existing levels.
Since you want the presentLevels array to be ordered by the number of the level, you'll need to iterate the levels array, and return a new array. You can do this easily with Array.map(). On each iteration take the current level from the existing Map, and if not found in existing return a new object with NA.
const levels = [1, 2, 3, 4]
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}]
const existingMap = new Map(arr.map(o => [o.LEVEL, o]))
const presentLevels = levels.map(LEVEL =>
existingMap.get(LEVEL) || { LEVEL, NAME1: 'NA' }
);
console.log(presentLevels)
You can make a loop with levels to get the items which arr doesn't have, then adding that items to arr
const levels = [1,2,3,4]
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}]
var items = levels.filter(level => !arr.find(item => item.LEVEL === level));
items.forEach(level => arr.push({LEVEL: level, NAME1: "NA"}));
console.log(arr.sort((a, b) => a.LEVEL - b.LEVEL));
You could first map the levels to the object array with all NA, and then iterate arr to replace those where necessary:
const levels = [1,2,3,4];
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}];
const result = levels.map(LEVEL => ({LEVEL, NAME1: "NA"}) );
for (let o of arr) result[o.LEVEL-1] = o;
console.log(result);
Although this executes two loops, they are not nested, and so this task is performed with linear time complexity (contrary to solutions that have a find call inside the loop).
maybe like this:
const levels = [1,2,3,4];
const arr = [{"LEVEL":1,"NAME1":"JACK"},{"LEVEL":3,"NAME1":"TOM"}];
for(var key_l in levels){
var found_levels = false;
for(var key_ar in arr){
if(arr[key_ar].LEVEL == levels[key_l]){
found_levels = true;
}
}
if(!found_levels){
arr.push({"LEVEL":levels[key_l],"NAME1":"NA"});
}
}
/* for result sorting, if need... */
arr.sort(function(a, b){
return a.LEVEL > b.LEVEL;
});
console.log(arr);

How to remove certain elements from an array into a new array and leave the others only the original array?

How to write a function to remove certain elements into a new array and leave the original array with only the remaining elements?
the first part is easy using a for loop pushing the even numbers into a new array but mutating the original array to leave only the odd numbers is hard
function remove(arr, cb){
var removed = [];
var newArr = [];
for(var i = 0; i < arr.length; i++) {
if(cb(arr[i], i, arr)) {
removed.push(arr[i]);
}
}
return removed;
}
Use an else statement to fill newArr with values that should stay in the original arr, then empty it using splice() before copying the items from newArr back into it.
function remove (arr, cb) {
var removed = [];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (cb(arr[i], i, arr)) {
removed.push(arr[i]);
} else {
newArr.push(arr[i]);
}
}
arr.splice(0);
for (var i = 0; i < newArr.length; i++) {
arr.push(newArr[i]);
}
return removed;
}
Welcome to Stackoverflow!
Personally, I'd avoid anything that mutates an input parameter, as this increases code complexity and makes it hard to reason about what's happening from the calling side.
Instead, I'd write a method that returns an array of two arrays. This can be easily split into two variables at the calling end using by using array destructuring.
See the example below:
const splitArr = (arr, pred) =>
arr.reduce(
(prev, curr, idx) => {
prev[+pred(curr, idx, arr)].push(curr);
return prev;
}, [[], []]
);
// usage //
const myArr = [1, 2, 3, 4];
const [arr1, arr2] = splitArr(myArr, x => x > 2);
console.log(arr1);
console.log(arr2);
Because pred is a function that returns a boolean value, we can co-erce this value to 0 or 1 using +someBoolean. We can then use this value as an index to decide into which of the two output arrays the value should be pushed.
You were definitely on the right track with your solution, a couple tweaks and we can make it very readable and also very easy to work with. I tried to keep the format of what it looked like you were doing.
I do take advantage of destructuring here, this could be returned as just an object, and then reference the properties.
const myArr = [0,1,2,3,4,5,6,7,8,9,10];
const splitItems = (arr, logicFunc) => {
let secondSet = []
const firstSet = arr.filter(v => {
if (logicFunc(v)) return true
else secondSet.push(v)
})
return { firstSet, secondSet }
}
const myLogicFunc = v => (v < 3 || v == 9)
const { firstSet, secondSet } = splitItems(myArr, myLogicFunc)
console.log(`My first set: ${firstSet}`) // My first set: 0,1,2,9
console.log(`My second set: ${secondSet}`) // My second set: 3,4,5,6,7,8,10
/* OR without destructuring:
const myArrays = splitItems(myArr, myLogicFunc)
console.log(`My first set: ${myArrays.firstSet}`)
console.log(`My second set: ${myArrays.secondSet}`)
*/
Please let me know if you have any questions
In modern JavaScript apps we do not mutate arrays we create new array, this avoids side effects, so what we do is create two new arrays
const split = (source, conditionFunc) = [ source.filter(i => conditionFunc(i)), source.filter(i => !conditionFunc(i))];
Then you have an array of two arrays of the values that meed condition and those that don't and you have not caused any side effects.
const odssAndEvens = split(source, i => i % 2 === 1);
Or with reduce so you don't iterate the array twice
const split = (source, conditionFunc) = source.reduce((results, item) => {
if (conditionFunc(item)) {
results[0].push(item);
} else {
results[1].push(item);
}
return results;
}, [[],[]]);

How to add object inside array without reference

My code is so far
var chartSeriesArray = [{"EnableAnimation": true,"AnimationDuration": 1}];
let refArray = chartSeriesArray;
let clonedArray = [...chartSeriesArray]; // will clone the array
var x = [];
for(i=0;i<2;i++){
x.push(clonedArray);
}
x[0].foo = "bar";
console.log(x);
Console Output is
0:[{…}, foo: "bar"]
1:[{…}, foo: "bar"]
Whether I am trying to loop refArray or clonedArray in both the cases, it's added foo in both item 0 and 1, i want to add only in 0 for example.
Expected output is
0:[{…}, foo: "bar"]
1:[{…}]
I want to access 0 and 1 individually later.
I tried everything but nothing works, Any help is highly appreciated.
Further after all suggestions, when i am trying below code
var metadata =
{
"KPISDetail": [{
"ChartSeriesList": {
"EnableAnimation": true,
"AnimationDuration": 1
}
}, {
"ChartSeriesList": {
"EnableAnimation": true,
"AnimationDuration": 1
}
}]
}
var data = [];
var x = [];
for(var l=0;l<2;l++){
data.push(metadata.KPISDetail[l].ChartSeriesList);
x.push(...data.map(o => Object.assign({}, o)))
}
x[0].foo = "bar";
x[1].foo = "foo";
console.log(x);
Result should be 2 only because my loop is executing 2 times. But i am getting output 3 times, which is wrong. I am getting below output
You are pushing clonedArray into x 2 time but you forgot about both time you are using same variable so memory allocation of both are same so if you want to add something on x element they reflect on both. To achieve desire result that you can use like that -
var chartSeriesArray = [{"EnableAnimation": true,"AnimationDuration": 1}];
let refArray = chartSeriesArray;
let clonedArray = [...chartSeriesArray]; // will clone the array
var x = [];
for(i=0;i<2;i++){
x.push(JSON.parse(JSON.stringify(clonedArray))); // will create magic
}
x[0].foo = "bar";
console.log(x);
Updated Code -
var metadata =
{
"KPISDetail": [{
"ChartSeriesList": {
"EnableAnimation": true,
"AnimationDuration": 1
}
}, {
"ChartSeriesList": {
"EnableAnimation": true,
"AnimationDuration": 1
}
}]
}
var data = [];
var x = [];
for(var l=0;l<2;l++){
x.push(JSON.parse(JSON.stringify(metadata.KPISDetail[1].ChartSeriesList)))
}
x[0].foo = "bar";
x[1].foo = "foo";
console.log(x);
You should create array clone with cloned elements:
let clonedArray = chartSeriesArray.map((item) => Object.assign({}, item))
You can try with the following:
var x = [];
for(i=0;i<2;i++){
let real_clone = clonedArray.slice(0); // if you need to clone an array
let real_clone = JSON.parse(JSON.stringify(clonedArray)); // if you need to clone both array and object
x.push(real_clone);
}
Issue is you create a single cloned array and pushed in multiple time. You need to create a new cloned array for every single push.
var chartSeriesArray = [{"EnableAnimation":true,"AnimationDuration": 1}];
var x = [];
for(i=0;i<2;i++){
x.push([...chartSeriesArray]);
}
x[0].foo = "bar";
console.log(x);

Checking multiple variables with the same "rules"

I have to construct an array of objects. I can do it "long hand," but I'm hoping to find a way to iterate through some variables and check each at "push" them into the right spot in the array.
I have this:
//this is the starting array...I'm going to update these objects
operationTime = [
{"isActive":false,"timeFrom":null,"timeTill":null},//Monday which is operationTime[0]
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null}
];
//I get the below via an API call
var monHours = placeHours.mon_open_close;
var tueHours = placeHours.tue_open_close;
var wedHours = placeHours.wed_open_close;
var thuHours = placeHours.thu_open_close;
var friHours = placeHours.fri_open_close;
var satHours = placeHours.sat_open_close;
var sunHours = placeHours.sun_open_close;
var sunHours = placeHours.sun_open_close;
//here's where I'm stuck.
if (monHours.length>0){
var arr = monHours[0].split("-");
operationTime[0].isActive= true;
operationTime[0].timeFrom= arr[0];
operationTime[0].timeTill= arr[1];
}
else {
operationTime[0].isActive= false;
}
My if/else works perfectly in the above example using Monday, but I don't want to write this for seven days of the week making it unnecessarily complicated. How could I condense this into a single "function" that'll test each variable and push it into the array object in the correct position?
I guess you can put the keys in an array, and then use forEach loop through operationTime and update the object based on the index:
operationTime = [
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null},
{"isActive":false,"timeFrom":null,"timeTill":null}
];
// make an array of keys that has the same order of the operationTime
var keys = ['mon_open_close', 'tue_open_close', 'wed_open_close', 'thu_open_close', 'fri_open_close', 'sat_open_close', 'sun_open_close'];
var placeHours = {'mon_open_close': ['08:00-17:00'], 'tue_open_close':[], 'wed_open_close':[], 'thu_open_close':[], 'fri_open_close':[], 'sat_open_close':[], 'sun_open_close':['10:20-15:30']}
operationTime.forEach( (obj, index) => {
var dayHours = placeHours[keys[index]];
if(dayHours.length > 0) {
var arr = dayHours[0].split("-");
obj.isActive= true;
obj.timeFrom= arr[0];
obj.timeTill= arr[1];
}
})
console.log(operationTime);
You can try this way with foreach all days's hour,
$all_hours = [monHours, tueHours , wedHours , thuHours , friHours , satHours ,sunHours];
foreach($all_hours as $k=>$hours){
if ($hours.length>0){
$arr = $hours[k].split("-");
operationTime[$k].isActive= true;
operationTime[$k].timeFrom= $arr[0];
operationTime[$k].timeTill= $arr[1];
}
else {
operationTime[$k].isActive = false;
}
}
You can use Object.entries() to iterate properties and values of an object as an array, .map() to define and include index of iteration in block of for..of or other loop. The index is utilized to reference object at index of operationTime array
for (let
[key, prop, index]
of
Object.entries(placeHours)
.map(([key, prop], index) => [key, prop, index]))) {
if (prop.length > 0 ) {
let [arr] = prop.split("-");
operationTime[index].isActive = true;
operationTime[index].timeFrom = arr[0];
operationTime[index].timeTill = arr[1];
}
}

Categories

Resources