React create object of simple object with map iterator - javascript

I'm studying React and json objects, but I can't obtain what i want:
Here is the code:
const selectOptions1 = {
9: 'good',
14: 'Bad',
26: 'unknown'
};
const selectOptions2 = options.map((item) => {
return (
{ [item.value]:item.label }
)
})
console.log(selectOptions1) // {9:good, 14:bad, 26:unknown}
console.log(selectOptions2) // [{…}, {…}, {…}] -> 0: {9: "good"} 1: {14: "bad"} 2: {26: "unknown"}
How can I create an object like selectOptions1 using map (instead of the structure like in selectOptions2)?

you should use Reduce instead of map
const options = [
{value: 1, label : 'one'},
{value: 2, label : 'two'},
{value: 3, label : 'three'},
{value: 41, label : 'four'},
{value: 32, label : 'five'},
]
var obj = options.reduce((accumulator, current) => {
return {
[current.value]: current.label,
...accumulator,
}
}, {});
console.log(obj);
Because map transform every item into a new one and returns a list of the same length with the transformation applied. you are transforming every {value, label} object into a new {value, label} object.
reduce accumulates and returns only one result, that can be a list or something else if you have creativity with it, here i'm using the Spread operator to accumulate keys in one object.

Related

How to map or assign an entry to an array-item based on some of this item's conditions?

I have array of objects,
if the name is xx then push xitems to that object and
if the name is yy then push yitems to that object
Below is the code tried , and also should not use spread operator
const result = [];
var ss=arrobj.forEach(function(e){
if(e.name === 'xx'){
result.push({id: e.id, name: e.name, country:e.country, others: xitems})
}
if(e.name === 'yy'){
result.push({id: e.id, name: e.name, country:e.country, others: yitems})
}
return result;
});
var arrobj =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
]
xitems =[
{title: "Finance", valid: true}
]
yitems =[
{title: "Sales", valid: true}
]
Expected Output
[
{id:1, name: "xx", country: "IN",
others:[
{title: "Finance", valid: true}
]
},
{id:2, name: "yy", country: "MY",
others: [
{title: "Sales", valid: true}
]
},
]
You should use .map for this.
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj.map((item) => {
if (item.name === "xx") {
item.others = xitems;
} else if (item.name === "yy") {
item.others = yitems;
}
return item;
});
console.log(result);
Your code works, the only issue that I identified are.
There is no need to assign var ss with arrobj.forEach. Because Array.forEach donot return a value.
No need of return result; inside Array.forEach.
Also as an improvement you can simply assign the object with key others like Object.assign({}, e, { others: xitems }), rather than returning individual key value.
Working Fiddle
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
]
const xitems = [
{ title: "Finance", valid: true }
]
const yitems = [
{ title: "Sales", valid: true }
]
const result = [];
arrobj.forEach(function (e) {
if (e.name === 'xx') {
result.push(Object.assign({}, e, { others: xitems }))
}
if (e.name === 'yy') {
result.push(Object.assign({}, e, { others: yitems }))
}
});
console.log(result)
Variables are references to an object that has a value, variables do not store values. It is pointless to try to use a variable in that manner unless you have specific parameters. If you insist on a condition then you need to identify xitems and yitems by the objects values and/or properties or by the order they came in. If you have dynamic data how would you know what xitems or yitems really is?
The example below has been made reusable as long as you meet these requirements:
Must have an array of objects as a primary parameter.
Must have at least one array of objects for each object in the primary array. If there's more the rest will be ignored.
The secondary array of objects must be in the order you want then to end up as.
The second parameter is a rest parameter (not a spread operator, although I have no idea why OP does not want to use it). This will allow us to stuff in as many object arrays as we want.
const distOther = (main, ...oAs) => {...
Next we create an array of pairs from all of the secondary arrays
let others = oAs.map(sub => ['others', sub]);
// [['others', [{...}]], [['others', [{...}]], ...]
Then we turn our attention to the primary array. We'll work our way from the inside out. .map() each object as an array of pairs by Object.entries():
main.map((obj, idx) =>
// ...
Object.entries(obj)
// ...
// [{A: 1, B: 2}, {...}] => [[['A', 1], ['B', 2]], [[...], [...]]]
Then .concat() (a spead operator would be more succinct) each array of pairs with that of the secondary array of pairs corresponding to the current index (you'll need to wrap each secondary array in another array, so the return will level off correctly):
// main.map((obj, idx) =>
// ...
// Object.entries(obj)
.concat([others[idx]])));
// [[['A', 1], ['B', 2], ['others', [{...}]], [[...], [...], ['others', [{...}]]]
Finally we'll use Object.fromEntries() to convert each array of pairs into an object.
// main.map((obj, idx) =>
Object.fromEntries(
// Object.entries(obj)
// .concat([others[idx]])));
// [{'A': 1, 'B': 2, 'others': [{...}]},...]
const objArr =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
];
const x =[
{title: "Finance", valid: true}
]
const y =[
{title: "Sales", valid: true}
]
const distOther = (main, ...oAs) => {
let others = oAs.map(sub => ['others', sub]);
return main.map((obj, idx) =>
Object.fromEntries(
Object.entries(obj)
.concat([others[idx]])));
};
console.log(distOther(objArr, x, y));
I would choose a map based approach as well but without the if clauses which explicitly check for expected values of the mapped item's name property.
The approach instead utilizes map's 2nd thisArg parameter which gets applied as the mapper functions this context. Such an additional object can be provided as a map/index of custom key value pairs where key equals a mapped item's name.
Thus the mapper implementation features generic code, and due to the this binding it will be provided as function statement which makes it also re-usable and, if properly named, readable / comprehensible / maintainable too.
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item,
{ others: index[item.name] ?? [] },
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
As one can see, the above implementation via Object.assign creates a new object from each mapped arrobj item. Thus the original item-references remains untouched / non mutated. It does not apply for the items of xitems and yitems since both array references are directly assigned each to its newly created others property. The above log does reflect this.
In case the goal was an entirely reference free data structure one needs to slightly change the Object.assign part of assignBoundNamedValueAsOthers ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item, {
others: (index[item.name] ?? [])
// dereference the `others` items as well.
.map(othersItem =>
Object.assign({}, othersItem)
)
},
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
In case the OP does not need to care about immutability, the entire process then changes from a map task to a forEach task, where assignBoundNamedValueAsOthers does directly change/mutate each currently processed item of arrobj, thus forEach does not return any data but always the undefined value ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// mutate the original reference of the currently
// processed `item` by directly assigning, according
// to `item.name`, the bound named value as `others`.
Object.assign(
item,
{ others: index[item.name] ?? [] },
);
// no explicit return value due to
// going to be used as a `forEach` task.
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
// mutates each item of `arrobj`.
arrobj.forEach(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }

How do I convert this javascript object into an array using javascript without arrow functions?

This comes through GTM as an object that I have to convert to an array, so that I can loop through it.
I've written a forEach statement for it, but I can't seem to format this properly to work.
(full disclosure, I'm not a developer, I'm just trying to muddle my way through GTM)
I've tried using Object.entries(obj), but the result was multiple arrays.
{
0: {
category_id: '',
cart_entry_id: 0,
quantity: 3,
product_id: '678294',
unit_price: 5.29,
product_name: 'Office Depot® Brand 8-Pocket Poly Organizer, Assorted Colors (No Color Choice)',
},
2: {
category_id: '543867',
cart_entry_id: 2,
quantity: 1,
product_id: '448906',
unit_price: 34.99,
product_name: 'Realspace® All-Pile Studded Chair Mat, 36" x 48";, Clear',
},
3: {
category_id: '543867',
cart_entry_id: 3,
quantity: 1,
product_id: '493876',
unit_price: 179.99,
product_name: 'Realspace® MFTC 200 Mesh Multifunction Ergonomic Mid-Back Task Chair, Black',
}
}
If you just have any object like this:
{
0: 'some data',
1: 'some data',
2: 'some data'
}
You can easily turn it into an array with this:
const input = {
0: 'some data',
1: 'some data',
2: 'some data'
};
const output = Object.values(input);
console.log(output);
If you need to ensure the keys are always in the same order (which you probably should) you can add a sort on it first.
const input = {
0: 'some data',
1: 'some data',
2: 'some data'
};
// entries turns the object into an array of arrays with each
// entry being [key, value].
const output = Object.entries(input)
.sort((a, b) => a[0] - b[0])
.map(i => i[1]);
console.log(output);
Since you asked without array functions, just change the arrow functions to not arrow functions (though not sure why you'd want to):
const input = {
0: 'some data',
1: 'some data',
2: 'some data'
};
// entries turns the object into an array of arrays with each
// entry being [key, value].
const output = Object.entries(input)
.sort(function (a, b) { return a[0] - b[0] })
.map(function (i) { return i[1] });
console.log(output);
Assuming that this object is something you have already and your question is containing a printout of that object.
for(var i in json_data)
result.push([i, json_data [i]]);
check out this question for a more through answer.
Assuming that you object is an ecommerce transaction (but could be cart, or any other) object from dataLayer, and that you'd like to convert it to an array.
set ecommerce object as DL variable
DL variable: ecommerce.purchase object
so it would look like this:
GTM debugger: ecommerce object
2] convert it to an array using Custom JS variable:
function(){
var a = JSON.stringify({{DL EE purchase array}});
return a;
}
That would convert ecommerce.purchase from object into an array [string data type].

Convert object property numeric value to string and append to object as new key value

0: {Number: 1 }
1: {Number: 2 }
I am using lodash and react. I cant convert the number to a string but not add the value back into the output. I need something that looks like this:
0: {Number: 1, newNumber:"1" }
1: {Number: 2, newNumber: "2" }
I tried using .push, but this just added it as a new object e.g.
0: {Number: 1, }
1: {Number: 2, }
3: {newNumber: "1"}
I can't push into its corresponding object...
This can be done using Array.map
var x = [{
Number: 1
}, {
Number: 2
}];
var y = x.map(el => {
el.newNumber = el.Number.toString();
return el;
});
console.log(y);
You can iterate over the data with Array.prototype.map and add the additinal key to the Object:
var data = [{Number: 1 }, {Number: 2 }];
var result = data.map(el => ({...el, newNumber: String(el.Number)}))
console.log(result);

map array of object by property

I have this (says it's Object A)
[{grade:1},{grade:2},{grade:3}] till 100th.
how to map this existing data (says its name is object B) into them?
[
{grade:1,name:'alice',address:{poscode:123},tel:324}
{grade:5,name:'wonder',address:{poscode:123},tel:1234223},
{grade:90,name:'james',address:{poscode:234},tel:324}]
]
Says grade 50, it doesn't match any of Object B, the final result should also have the name and address property, assign the value null to them to make the array consistent. I issue is what if there's other property in Object B if I loop using Object A?
If I understand the issue correctly, you can use Object A as your map source, then use Object.assign to copy individual properties from Object B as well as adding in some defaults:
const objA = [{grade:1},{grade:2},{grade:3}];
const objB = [
{grade:1,name:'alice',address:{poscode:123},tel:324},
{grade:5,name:'wonder',address:{poscode:123},tel:1234223},
{grade:90,name:'james',address:{poscode:234},tel:324}
];
const objC = objA.map(rootObject => Object.assign(
// A new object with some defaults
{ name: null, address: null, tel: null },
// The source object from objA
rootObject,
// The data object from objB, if any
objB.find(detail => detail.grade === rootObject.grade)
)
);
console.log(objC);
You can achieve that using convenient Array methods. See snippet below:
const a = [
{grade: 1},
{grade: 2},
{grade: 3},
{grade: 4},
{grade: 5},
{grade: 90},
{grade: 100}
];
const b = [
{grade:1,name:'alice',address:{poscode:123},tel:324},
{grade:5,name:'wonder',address:{poscode:123},tel:1234223},
{grade:90,name:'james',address:{poscode:234},tel:324}
];
let result = a.map(aItem => {
let match = b.find( bItem => aItem.grade === bItem.grade );
if(!match){
return Object.assign({}, aItem, { name: null, address: {}, tel: null });
} else {
return match;
}
});
console.log(result);

How do I get a specific object from an immutable js map by value?

I created an immutable map (with Immutable-JS) from a list of objects:
var result = [{'id': 2}, {'id': 4}];
var map = Immutable.fromJS(result);
Now i want to get the object with id = 4.
Is there an easier way than this:
var object = map.filter(function(obj){
return obj.get('id') === 4
}).first();
Essentially, no: you're performing a list lookup by value, not by index, so it will always be a linear traversal.
An improvement would be to use find instead of filter:
var result = map.find(function(obj){return obj.get('id') === 4;});
The first thing to note is that you're not actually creating a map, you're creating a list:
var result = [{'id': 2}, {'id': 4}];
var map = Immutable.fromJS(result);
Immutable.Map.isMap(map); // false
Immutable.List.isList(map); // true
In order to create a map you can use a reviver argument in your toJS call (docs), but it's certainly not the most intuitive api, alternatively you can do something like:
// lets use letters rather than numbers as numbers get coerced to strings anyway
var result = [{'id': 'a'}, {'id': 'b'}];
var map = Immutable.Map(result.reduce(function(previous, current) {
previous[ current.id ] = current;
return previous;
}, {}));
Immutable.Map.isMap(map); // true
Now we have a proper Immutable.js map which has a get method
var item = Map.get('a'); // {id: 'a'}
It may be important to guarantee the order of the array. If that's the case:
Use an OrderedMap
Do a set method on the OrderedMap at each iteration of your source array
The example below uses "withMutations" for better performance.
var OrderedMap = Immutable.OrderedMap
// Get new OrderedMap
function getOm(arr) {
return OrderedMap().withMutations(map => {
arr.forEach(item => map.set(item.id, item))
})
}
// Source collection
var srcArray = [
{
id: 123,
value: 'foo'
},
{
id: 456,
value: 'bar'
}
]
var myOrderedMap = getOm(srcArray)
myOrderedMap.get(123)
// --> { id: 123, value: 'foo' }
myOrderedMap.toObject()
// --> { 123: {id: 123, value: 'foo'}, 456: {id: 456, value: 'bar'} }
myOrderedMap.toArray()
// --> [ {id: 123, value: 'foo'}, { id: 456, value: 'bar' } ]
When using fromJS for array, you'll get List not map. It will be better and easier if you create a map. The following code will convert the result into Immutable map.
const map = result.reduce((map, json) =>
map.set(json.id, Immutable.fromJS(json))
, Map());
Now, you can
map.get('2'); //{'id': 2}
Note, if the result has nested structure and if that has array, it will be a List with the above code.
With ES2015 syntax (and constants):
const result = map.find(o => o.get('id') === 4);
Is there already a way thats easier? I don't know. but you can write your own function. Something like this should work:
var myFunc = function(id){
var object = map.filter(function(obj){return obj.get('id') === id}).first();
return object;
}
Then you would just do:
var myObj = myFunc(4);

Categories

Resources