Pushing an object to array using foreach - javascript

let inputValues = [];
for (let i = 0; i < inputs.length; i++) {
let inputValue = inputs[i].value;
inputValues.push(inputValue)
}
let newCar = {
Model: inputValues[0],
Brand: inputValues[1],
Date: inputValues[2],
Horsepower: inputValues[3],
Transmission: inputValues[4],
Class: inputValues[5]
}
newData.push(newCar)
Can someone help me push newCar object to newData array using foreach loop. inputs are my inputs. i need to add the input values to my object keys. and push the object to the array. i need to do this in a way where i dont have newCar object declared like this.

There's no need for the loop or the newCar variable, you can put the object directly in the call to push()
newData.push({
Model: inputs[0].value,
Brand: inputs[1].value,
Date: inputs[2].value,
Horsepower: inputs[3].value,
Transmission: inputs[4].value,
Class: inputs[5].value
});
But it should work the same either way.

If we assume that your number of labels is the same as your number of inputs. Then we can do all this work in one loop as seen in the example code snippet example. Feel free to run it and see how it all works.
That being said, it is best to add your divs with the labels themselves so then you can gather the data from the divs rather than having to deal with fixed indexes which could become a problem as you add more labels.
<div data-label="Model">Toyota</div>
Then you will be able to do the below by doing this assuming inputs is an array of divs defined as above
let newData = [];
inputs.forEach((input) => newData.push({
[input.attr('data-label')]: input.text()
}))
But you could shorting this even more by just using a map
let newDate = inputs.map((input) => ({
[input.attr('data-label')]: input.text()
}))
// This method assumes that your divs will have the same number of labels
// We will assume input values are as such. But you can change it to be array of divs
let inputs = [{ value: 'Corolla' }, { value: 'Toyota' }, { value: '2014' }, { value: 'coolHorsies' }, { value: 'coolTransmission' }, { value: 'coolClass' }]
let labels = ['Model', 'Brand', 'Date', 'Horsepower', 'Transmission', 'Class'];
let newData = [];
inputs.forEach((input, idx) => newData.push({
[labels[idx]]: input.value,
}))
console.log(newData)

Related

JS - How to add key:value pairs from objects nested in arrays to other objects nested in another array

I know it has been countlessly asked and I assure you that I've read a lot of posts, articles, etc., and watched a lot of videos but nothing seems to click.
so there we go :
Here are 2 arrays with partial information about every person
let arr1 = [{id:00, name:Ben, city:Philadelphia}, {id:01, name:Alice, city:Frankfurt}, {id:02, name:Detlef, city:Vienna}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
And there is the desired final result: an array including the name, city, and age of each person
let arr3 = [{name:Ben, city:Philadelphia, age:39}, {name:Alice, city:Frankfurt, age:75 }, {name:Detlef, city:Vienna, age:18}]
What's the situation? Two arrays both containing objects. each nested object has an id. That id is the common key in each array of objects.
What do you want to do? : I want to create a third array including information from both arrays (from arr1: name and city; from arr2:age).
What have you tried so far? : I couldn't manage to achieve anything worth showing. this minimal example is intended to show you a simple example of my current situation which is: I've got an array that is in the LocalStorage on one hand and an API on the other, both contain some info regarding particular objects (let's say, persons). I want to create an array that will contain all the information regarding each person for easier manipulation afterward (DOM generation, etc.).
I've managed to store both arrays in two "local" arrays but the problem is still there: I can't figure out how to make an array where items are getting their key/value from two separate sources.
Thank you for your help!
You can use reduce method on the arr with array as an inital value, and inside try to find the corrospending item with same id and destruct the object from the id and merge the two object with spread operator.
let arr1 = [{id:00, name:'Ben', city: 'Philadelphia' }, {id:01, name:'Alice', city:'Frankfurt'}, {id:02, name:'Detlef', city:'Vienna'}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
const result = arr1.reduce((acc, { id: id1, ...rest1 }) => {
const { id: id2, ...rest2 } = arr2.find(i => i.id === id1)
acc.push({ ...rest1, ...rest2 })
return acc;
}, [])
console.log(result)
You can solve it in various ways, here first I have implemented a dict with key as id to get the value in O(1) while iterating arr2.
So the overall time complexity is O(n+k) where n is len of arr1 and k is len of arr2.
let arr1 = [{id:00, name: "Ben", city: "Philadelphia"}, {id:01, name:"Alice", city:"Frankfurt"}, {id:02, name:"Detlef", city:"Vienna"}];
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}];
const refMapById = arr1.reduce((refMap, {id, name, city}) => {
refMap[id] = {name, city};
return refMap;
}, {});
const result = arr2.reduce((resultArray, {id, age}) => [...resultArray, { ...refMapById[id],age}], []);
console.log(result);
Cheers!
It will be worth creating a dictionary from one of the arrays anyway since using .find() inside of .reduce() adds an unnecessary nested loop. But instead of reducing the second array as was suggested you can simply .map() it into the result array, like so:
let arr1 = [{ id: 00, name: "Ben", city: "Philadelphia" }, { id: 01, name: "Alice", city: "Frankfurt" }, { id: 02, name: "Detlef", city: "Vienna" }];
let arr2 = [{ id: 02, age: 18 }, { id: 00, age: 39 }, { id: 01, age: 75 }];
const groupedById = arr1.reduce((group, person) => {
group[person.id] = person;
return group;
}, {});
const result = arr2.map((personPartFromSecondArray) => {
const personPartFromFirstArray = groupedById[personPartFromSecondArray.id];
if (typeof personPartFromFirstArray !== "undefined") {
return { ...personPartFromFirstArray, ...personPartFromSecondArray }
}
return personPartFromSecondArray;
});
console.log(result);

How can I "unstack" my JSON data in d3.js?

I have data in a JSON array that looks like this:
[{"TEACHER":3.7},{"STUDENT":1.9}]
My desired output is a JSON array that looks like this:
var statements = [
{
name: "TEACHER",
value: 3.7
},
{
name: "STUDENT",
value: 1.9
}
];
How can I "unstack" the data I have to add the variable labels like I want?
This is what I came up with. There might be a more elegant way to do this though.
var x = [{"TEACHER":3.7},{"STUDENT":1.9}];
console.log(unstack(x));
function unstack(stacked){
var unstacked = [];
stacked.forEach((element) => {
unstacked.push({
name: Object.keys(element)[0],
value: Object.values(element)[0]
});
});
return unstacked;
}
Is it the only key your original object has? If that's the case, you can use the only item Object.keys() or Object.entries() return. If there are other attributes you could look for a match in the key and process it accordingly.
const input = [{"TEACHER":3.7},{"STUDENT":1.9}];
const output = [];
input.forEach(item => {
const key = Object.keys(item)[0];
output.push({name: key, value: item[key]});
});
console.log(output);

Return JSON Object by Value of a Key

I have a huge nested JSON object, and need to find a specific one by a certain value of a certain key.
For example:
[ {
id: 't53',
action: 'Boot',
time: 2019-04-21T17:58:34.579Z
},
{
id: 't54',
action: 'Reset',
time: 2019-04-24T17:57:33.549Z
} ]
So, if need to find the object where action is Boot, and the result must be:
{
id: 't54',
action: 'Boot',
time: 2019-04-24T17:57:33.549Z
}
You can use the Array.find method to get the first item that matches the condition.
const item = objs.find(obj => obj.action === 'Boot');
If you want to find the first element from last, you could create a shallow copy of the array and reverse it.
const item = objs.slice().reverse().find(obj => obj.action === 'Boot');
var data = [{
id: 't53',
action: 'Boot',
time: '2019-04-21T17:58:34.579Z'
},
{
id: 't54',
action: 'Boot',
time: '2019-04-24T17:57:33.549Z'
}];
var result = data.filter(a => a.action === 'Boot');
console.log(result);
You loop over the array and check each item action key is you want or not.

Is there a better way to sort through an array of objects to dynamically generate HTML elements separated by value?

I'm looping through an array of objects to dynamically generate HTML sorted by one or more values found in the objects.
Data:
data = [ { value: "FirstValue", category: "FirstCategory" }, { value: "SecondValue", category: "FirstCategory" }, { value: "ThirdValue", category: "SecondCategory" }, { value: "FourthValue", category: "FirstCategory" }]
My solution starts by creating an empty array, iterating through objects in data checking whether categories array contains object category.
If category in categories, I find the HTML with the category value, append necessary values inside.
If category not in categories, I push the new category into categories array, create a new HTML div with the category value inside and append an HTML div with the object value inside that newly created category div.
categories = [];
for (var i = 0; i < data.length; i++) {
value = data[i][value]
category = data[i][category];
if (categories.includes(category)) {
console.log("Category already in array");
existingCatBlock = findHTMLWhereCatIsCat(category);
newHTMLBlockWithValue = newBlock(value);
existingCatBlock.append(newHTMLBlockWithValue);
}
else {
categories.push(category);
newCategoryBlock = newBlockWithCat(category);
newHTMLBlockWithValue = newBlock(value);
newCategoryBlock.append(newHTMLBlockWithValue);
mainHTMLContainer.append(newCategoryBlock);
}
}
Current solution gets the job done, but maybe there are better, more elegant known ways to do this, especially in the case there were more values to sort by.
Mainly for readability, I would try manipulating the array first, sorting it in the way you want them, and then afterwards add everything on the screen.
I would first create a dictionary from your data whose keys would be the categories and the values would be arrays with your categories values. Array.reduce() can be used to build it. This gives the following object:
{
"FirstCategory": [
"FirstValue",
"SecondValue",
"FourthValue"
],
"SecondCategory": [
"ThirdValue"
]
}
Then you can iterate over the entries of this dictionary using Object.entries(), Array.forEach() and Array.map() to build each category, add its children and insert the whole category in the DOM.
That way, you don't have to keep track of which categories already exist in the DOM. You just have to insert it once, with all of its children, thanks to the intermediate mapping of categories to values.
const data = [
{ value: "FirstValue", category: "FirstCategory" },
{ value: "SecondValue", category: "FirstCategory" },
{ value: "ThirdValue", category: "SecondCategory" },
{ value: "FourthValue", category: "FirstCategory" }
];
const dataByCategories = data.reduce((acc, { value, category }) => {
acc[category] = [...(acc[category] || []), value];
return acc;
}, {});
const mainHTMLContainer = document.querySelector('#main');
Object.entries(dataByCategories).forEach(([category, values]) => {
const valuesHTML = values.map(newBlock).join('');
const categoryBlock = newBlockWithCat(category, valuesHTML);
// A single appendChild is done for each category
mainHTMLContainer.appendChild(categoryBlock);
});
function newBlock(value) {
return `<div class="value">html for ${value}</div>`;
}
function newBlockWithCat(category, values) {
const div = document.createElement('div');
div.classList.add('category');
div.innerHTML = values;
return div;
}
.value {
padding: 2px;
}
.category {
display: inline-block;
border: 1px solid black;
width: 150px;
margin: 5px;
}
<div id="main">
</div>

filter existing array of object using simple map and filter es6

Try to avoid using any library as I just need a simple script. I want to get non existing record from existing array.
input = [{name: 'james'}, {name: 'jane'}]
existing = [{name: 'james'}]
//do something
expected input to become
[{name: 'jane'}]
I tried this
let input = [{
name: 'yahoo.com',
},{
name: 'google.my',
}]
existing = (existing || []).map(o => ({name: o.name})) //clean up data from backend [{name:'google.my'}]
input = (input || []).map(o => o.name) //just in case input has more property in the future
input = existing.filter(o => !o.name.includes(input))
console.log(input)
Somehow I still don't get what I want (expect input to be [{name: 'yahoo.com'}], what is missing? I couldn't spot it.
You could filter with a lookup with find.
var input = [{ name: 'james' }, { name: 'jane' }],
existing = [{ name: 'james' }],
result = input.filter(({ name }) => !existing.find(o => o.name === name));
console.log(result);
Array.prototype.filter, Array.prototype.map, and Set can be combined using a closure to detect missing elements between arrays of objects using keys.
See below for a practical example.
// Input.
const input = [{name: 'james'}, {name: 'jane'}]
// Existing.
const existing = [{name: 'james'}]
// Missing (B elements from A).
const missing = (A, B) => (s => A.filter(({name}) => !s.has(name)))(new Set(B.map(({name}) => name)))
// Output.
const output = missing(input, existing)
// Proof.
console.log(output)
You can use filter and find
let input = [{name: 'james'}, {name: 'jane'}];
let existing = [{name: 'james'}];
let result = input.filter(v => !existing.find(o => o.name == v.name));
console.log(result);
You can use a combination of two Array#filter.
The first one is looping through your input array, while the second one loops through your existing array to check if each input value is contained inside existing.
let input = [{name: 'james'}, {name: 'jane'}];
let existing = [{name: 'james'}];
let res = input.filter(a => !existing.filter(b => b.name == a.name).length);
console.log(res);
First, don't reuse variable names, it's confusing (you have two separate things called input.
Second, don't do unnecessary loops. Do a filter right out of the gate and then map to get an array of names (or skip the map altogether if you don't really need it)
let input = [
{
name: 'yahoo.com'
},
{
name: 'google.my'
}
]
//all names in existing that are also in input
(existing || [])
//I used some instead of includes
.filter(o => !(input || []).some(i => i.name == o.name))
.map(o => o.name);
MDN Array.prototype.some

Categories

Resources