I have a object variable and i want to push into my object a new { key: "value" } but with a loop and using loop index.
Something like this:
let headers = {
product_title: "Product Name",
action: "Status",
quantity: "Quantity",
priority: "Priority",
};
for (let i = 0; i < bigger; i++) {
headers = { ...headers, ...{ 'org_{i}': i } };
}
is there a way to do something like this or add unique key with indexes?
Finally i need something like below:
let headers = {
...old data
key_1: "",
key_2: "",
key_3: "",
};
There's an ES6 thing called "computed properties" which allows regular JS enclosed in [] to form a string key...
let headers = {
product_title: "Product Name",
action: "Status",
quantity: "Quantity",
priority: "Priority",
};
for (let i = 0; i < 5; i++) {
headers = { ...headers, ['key_' + i]: i }
}
console.log(headers)
Neat, but this creates a throw-away object for each iteration. Skipping the literal with the spread, you can use older JS, more efficiently...
let headers = {
product_title: "Product Name",
action: "Status",
quantity: "Quantity",
priority: "Priority",
};
for (let i = 0; i < 5; i++) {
headers['key_' + i] = i
}
console.log(headers)
To add new key-value into object you can literally just use
headers[key] = value
But if you are intending to set keys dynamically I suggest you to check this out
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map
Try something like below
const output = [...Array(bigger)].reduce((acc, curr, index) => {
return ({ ...headers, ...acc, [`org_${index}`]: index })
}, {});
Related
how to get the value in any way if key does match with "Item"
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
console.log(data[i].includes("Item"));
//Expecting phone and case
}
for-in allows you to loop through the keys in an object. Not to be confused with for-of, which loop through elements in an array.
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
for(let datum of data)
{
for(let key in datum)
{
if(key.includes("Item"))
{
console.log(datum[key]);
}
}
}
In the simple way just change data[i].includes("Item") to data[i].keys().includes("Item").
BUT! Could we have some alternative data set here? For example:
const data = [{
"Item-55566": "phone",
"SomeKey: "Some Value",
123123: "Numeric key with value"
},
{
"Items-44555": "Case",
"Another-key": "Another value"
}
];
In this case you need to put some changes in your code to find correct keys & values:
for(let i = 0; i<data.length; i++) {
data[i].keys().forEach(v=>{
String(v).includes("Item") && console.log("Got index: ${i}, key: ${v}, value: ${data[i][v]}")
})
}
The for loop iterates through the two objects, so you can check to see whether the object has that particular property using hasOwnProperty()
const data = [
{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
},
];
/* How to get value if index found by Item */
for (let i = 0; i < data.length; i++) {
if (data[i].hasOwnProperty("Item-55566")) {
console.log(data[i]);
}
}
If you want to keep your loop (good that it's only one loop compared to other answers) you can do it with Object.keys and values:
const data = [{
"Item-55566": "phone",
},
{
"Items-44555": "Case",
}
];
/* How to get value if index found by Item */
for(let i = 0; i<data.length; i++) {
if(Object.keys(data[i])[0].includes('Item')){
console.log(Object.values(data[i])[0]);
}
}
You can use .filter to filter all items of the data array which includes Item text.
Then you can use .map to render new value from each object comes from data array.
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var filteredItems = data.filter(item => Object.keys(item)[0].includes("Item"));
console.log(filteredItems.map(item => Object.values(item)[0]));
Refactor code - By using .reduce()
const data = [
{"Item-55566": "phone", },
{ "Items-44555": "Case",},
{ "Other-44555": "Nope",}];
var res = data.reduce((prev, curr) =>
{
var entries = Object.entries(curr)[0];
if(entries[0].includes("Item"))
prev.push(entries[1]);
return prev;
}, []);
console.log(res);
I currently have an array that has the following structure:
data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
But I would like to restructure the array to get something like this:
data = [
{
name: "thing1",
info: [{
time: 100,
count: 3
}, {
time: 1000,
count: 7
}, {
}]
},
{
name: "thing2",
info: [{
time: 100,
count: 2
}, {
time: 1000,
count: 0
}, {
}]
}
];
So basically the key would have to be switched from time to name, but the question is how. From other posts I have gathered that using the map function might work, but since other posts had examples to and from different structures I am still not sure how to use this.
There are a number of ways to achieve this however, the key idea will be to perform a nested looping of both data items and their (nested) info items. Doing that allows your algorithm to "visit" and "map" each piece of input data, to a corresponding value in the resulting array.
One way to express that would be to use nested calls to Array#reduce() to first obtaining a mapping of:
name -> {time,count}
That resulting mapping would then be passed to a call to Object.values() to transform the values of that mapping to the required array.
The inner workings of this mapping process are summarized in the documentation below:
const data=[{time:100,info:[{name:"thing1",count:3},{name:"thing2",count:2},{}]},{time:1e3,info:[{name:"thing1",count:7},{name:"thing2",count:0},{}]}];
const result =
/* Obtain array of values from outerMap reduce result */
Object.values(
/* Iterate array of data items by reduce to obtain mapping of
info.name to { time, count} value type */
data.reduce((outerMap, item) =>
/* Iterate inner info array of current item to compound
mapping of info.name to { time, count} value types */
item.info.reduce((innerMap, infoItem) => {
if(!infoItem.name) {
return innerMap
}
/* Fetch or insert new { name, info } value for result
array */
const nameInfo = innerMap[ infoItem.name ] || {
name : infoItem.name, info : []
};
/* Add { time, count } value to info array of current
{ name, info } item */
nameInfo.info.push({ count : infoItem.count, time : item.time })
/* Compound updated nameInfo into outer mapping */
return { ...innerMap, [ infoItem.name] : nameInfo }
}, outerMap),
{})
)
console.log(result)
Hope that helps!
The approach I would take would be to use an intermediate mapping object and then create the new array from that.
const data = [{time: 100, info: [{name: "thing1", count: 3}, {name: "thing2", count: 2}, {}]}, {time: 1e3, info: [{name: "thing1", count: 7}, {name: "thing2", count: 0}, {}]} ];
const infoByName = {};
// first loop through and add entries based on the name
// in the info list of each data entry. If any info entry
// is empty ignore it
data.forEach(entry => {
if (entry.info) {
entry.info.forEach(info => {
if (info.name !== undefined) {
if (!infoByName[info.name]) {
infoByName[info.name] = [];
}
infoByName[info.name].push({
time: entry.time,
count: info.count
});
}
});
}
});
// Now build the resulting list, where name is entry
// identifier
const keys = Object.keys(infoByName);
const newData = keys.map(key => {
return {
name: key,
info: infoByName[key]
};
})
// newData is the resulting list
console.log(newData);
Well, the other guy posted a much more elegant solution, but I ground this one out, so I figured may as well post it. :)
var data = [
{
time: 100,
info: [{
name: "thing1",
count: 3
}, {
name: "thing2",
count: 2
}, {
}]
},
{
time: 1000,
info: [{
name: "thing1",
count: 7
}, {
name: "thing2",
count: 0
}, {
}]
}
];
var newArr = [];
const objInArray = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o)
return true;
}
return false;
}
const getIndex = (o, a) => {
for (var i=0; i < a.length; i += 1) {
if (a[i].name === o) {
return i;
}
}
return false;
}
const getInfoObj = (t, c) => {
let tmpObj = {};
tmpObj.count = c;
tmpObj.time = t;
return tmpObj;
}
for (var i=0; i < data.length; i += 1) {
let t = data[i].time;
for (var p in data[i].info) {
if ("name" in data[i].info[p]) {
if (objInArray(data[i].info[p].name, newArr)) {
let idx = getIndex(data[i].info[p].name, newArr);
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newArr[idx].info.push(newInfoObj);
} else {
let newObj = {};
newObj.name = data[i].info[p].name;
let newInfo = [];
let newInfoObj = getInfoObj(t, data[i].info[p].count);
newInfo.push(newInfoObj);
newObj.info = newInfo;
newArr.push(newObj);
}}
}
}
console.log(newArr);
try to use Object.keys() to get the key
I'm making Ajax calls to a page in ASP.NET Core 3.1.
The response is a JsonResult whose Value property is an instance of a custom class, itself containing various string and collection properties.
One of these collections is a Dictionary<string, string>, which I can then access in JavaScript along the following lines:
var dictionary = response.DictionaryObj;
for (key in dictionary) {
DoSomeStuff(key, dictionary[key]);
}
However another of these collections requires a non-unique 'key', and is currently a List<KeyValuePair>
This ends up in JavaScript as an array of objects, which I can access like this:
var kvps = response.KvpList;
for (i = 0; i < kvps.length; i++) {
var kvp = kvps[i];
DoSomeMoreStuff(kvp.key, kvp.value);
}
The latter seems far less elegant - is there a way of packaging up the KeyValuePairs in a way that would let me use the former syntax?
For Dictionary<string, string> you can use Object.entries()
For List<KeyValuePair> object destructuring
const dictionaryObj = {
a: 'somestring',
b: 42,
};
for (const [key, value] of Object.entries(dictionaryObj)) {
console.log(`${key}: ${value}`); // DoSomeStuff(key, value)
}
console.log('===========================================');
const kvpList = [
{ key: '1', value: 'v1' },
{ key: '2', value: 'v2' },
{ key: '3', value: 'v3' },
];
for (const { key, value } of kvpList) {
console.log(`${key}: ${value}`); // DoSomeMoreStuff(key, value)
}
If you have an object and you want to iterate through its properties, then we can use Object.entries method to get an array of a given object's own enumerable string-keyed property [key, value] pairs, and then just use loop foreach:
let input = { "workType": "NDB To Nice", "priority": 5, "name": "Joseph", "lastName": "Skeet" }
const fooFunctiion = (key, value) => {
console.log(`key: ${key}, value ${value}` )
}
Object.entries(input).forEach(([k, v]) => {
fooFunctiion(k, v)
});
If you have an array of objects, then you can use foreach method:
let input = [
{ "workType": "NDB To Nice", "priority": 5 },
{ "workType": "PDAD", "priority": 0 },
{ "workType": "PPACA", "priority": 0 },
{ "workType": "Retrigger", "priority": "5" },
{ "workType": "Special Intake Request Intake", "priority": "7" }
];
const fooFunction = (obj, index) => {
console.log('obj: ', obj, index )
}
input.forEach((obj, ind) =>
fooFunction(obj, ind)
);
I have several objects and I want to create another one that will have keys from a particular array (const props = []), and values from those objects - if it only exists in those objects, but if not - I want to push null or some other fake values.
My code:
const props = ["name", "price", "qty", "category"]
let len = props.length;
const obj_1 = {
name: "Product_1",
price: 120,
category: 'phone'
}
const obj_2 = {
name: "Product_2",
price: 7893,
category: 'program_eq',
qty: 5
}
const final_obj = {
name: ["Product_1", "Product_2"],
price: [120, 7893],
category: ["phone", "program_eq"],
qty: [null, 5]
}
I have spent lots of time with this problem and have some solution - but it gives me only the first object.
I am using lodash/map and it helps me to work with different type of collection.
You can see my solution bellow:
const final_obj = {};
const props = ["name", "price", "qty", "category"];
let len = props.length;
const obj = {
c1s6c156a1cascascas: {
item: {
name: "Product_1",
price: 120,
category: "phone"
}
},
c454asc5515as41cas78: {
item: {
name: "Product_2",
price: 7893,
category: "program_eq",
qty: 5
}
}
};
_.map(obj, (element, key) => {
console.log(element.item);
while (len) {
let temp = props.shift();
let tempData = [];
if (element.item.hasOwnProperty([temp])) {
tempData.push(element.item[temp]);
} else {
tempData.push("---");
}
final_obj[temp] = tempData;
len--;
}
});
console.log(final_obj);
//
category:["phone"]
name:["Product_1"],
price:[120],
qty:["---"],
You could do this with reduce() method that will return object and inside use forEach() loop.
const props = ["name", "price", "qty", "category"];
const obj = {"c1s6c156a1cascascas":{"item":{"name":"Product_1","price":120,"category":"phone"}},"c454asc5515as41cas78":{"item":{"name":"Product_2","price":7893,"category":"program_eq","qty":5}}}
const result = Object.values(obj).reduce((r, e) => {
props.forEach(prop => {
if(!r[prop]) r[prop] = []
r[prop].push(e.item[prop] || null)
})
return r;
}, {})
console.log(result)
This is how I would handle it:
const final_obj = { };
const props = ["name", "price", "qty", "category"];
const obj = {"c1s6c156a1cascascas":{"item":{"name":"Product_1","price":120,"category":"phone"}},"c454asc5515as41cas78":{"item":{"name":"Product_2","price":7893,"category":"program_eq","qty":5}}}
// set up each property as an empty array in the object
props.forEach(item => {
final_obj[item] = [];
});
// this iterates over every property in the object
_.forOwn(obj, value => {
props.forEach(item => {
// just push the values undefined or no into each property array
final_obj[item].push(value.item[item]);
});
});
console.log(final_obj);
You can do as well using some lodash functions.
Transform the array of props into an object which keys are the values of props and which values are extracted from the object. If the property doesn't exist in the object, return null.
const getValFromObj = (obj, key) => _.map(obj, _.partial(_.get, _, key, null));
const setValInResult = (res, key) => _.set(res, key, getValFromObj(obj, 'item.' + key));
const groupByProps = (props, obj) => _.transform(props, setValInResult, {});
const props = ["name", "price", "qty", "category"];
const obj = {
"c1s6c156a1cascascas": {
"item": {
"name": "Product_1",
"price": 120,
"category": "phone"
}
},
"c454asc5515as41cas78": {
"item": {
"name": "Product_2",
"price": 7893,
"category": "program_eq",
"qty": 5
}
}
}
console.log(groupByProps(props, obj));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.5/lodash.min.js"></script>
I have this Javascript object (that is created on-the-fly by my plugin code):
{
"field": {
"name": "Name",
"surname": "Surname"
},
"address": {
"street": "Street",
"number": 0,
"postcode": 0,
"geo": {
"city": "City",
"country": "Country",
"state": "State"
}
},
"options": [1,4,6,8,11]
}
I don't want to turn this object to a JSON string, but I want to turn this object into another object, but with each field represented by a string, like this:
{
"field[name]": "Name",
"field[surname]": "Surname",
"address[street]": "Street",
"address[number]": 0,
"address[postcode]": 0,
"address[geo][city]": "City",
"address[geo][country]": "Country",
"address[geo][state]": "State",
"options[0]":1,
"options[1]":4,
"options[2]":6,
"options[3]":8,
"options[4]":11
}
Scenario:
I dont know how the original object will look like (or how deep it'll be), since it's part of a plugin and I have no idea how people will build their forms
I'm going to put this new object inside a FormData object, if it would only accept objects, it would be easier, because JSON can't upload files, but FormData object can
As I said in the comments, you need a for...in [MDN] loop to iterate over the properties of the object and can use recursion to subsequently convert nested objects:
function convert(obj, prefix, result) {
result = result || {};
// iterate over all properties
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var value = obj[prop];
// build the property name for the result object
// first level is without square brackets
var name = prefix ? prefix + '[' + prop + ']' : prop;
if (typeof value !== 'object') {
// not an object, add value to final result
result[name] = value;
}
else {
// object, go deeper
convert(value, name, result);
}
}
}
return result;
}
// Usage:
var converted_data = convert(data);
DEMO
Still, I would recommend using JSON.
If you want to handle files as well, you might have to add an additional check for File objects. You'd want them raw in the result object:
else if (window.File && value instanceof File) {
result[name] = value;
}
// and for file lists
else if (window.FileList && value instanceof FileList) {
for (var i = 0, l = value.length; i < l; i++) {
result[name + '[' + i + ']'] = value.item(i);
}
}
It could be that the File (FileList) constructor is named differently in IE, but it should give you a start.
Not a big fan of reinventing the wheel, so here is how you could answer your question using object-scan. It's a great tool for data processing - once you wrap your head around it that is.
// const objectScan = require('object-scan');
const convert = (haystack) => objectScan(['**'], {
filterFn: ({ key, value, isLeaf, context }) => {
if (isLeaf) {
const k = key.map((e, idx) => (idx === 0 ? e : `[${e}]`)).join('');
context[k] = value;
}
}
})(haystack, {});
const data = { field: { name: 'Name', surname: 'Surname' }, address: { street: 'Street', number: 0, postcode: 0, geo: { city: 'City', country: 'Country', state: 'State' } }, options: [1, 4, 6, 8, 11] };
console.log(convert(data));
/* =>
{ 'options[4]': 11,
'options[3]': 8,
'options[2]': 6,
'options[1]': 4,
'options[0]': 1,
'address[geo][state]': 'State',
'address[geo][country]': 'Country',
'address[geo][city]': 'City',
'address[postcode]': 0,
'address[number]': 0,
'address[street]': 'Street',
'field[surname]': 'Surname',
'field[name]': 'Name' }
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan#13.7.1"></script>
Disclaimer: I'm the author of object-scan