Why are the following logs logging different values (array loop)? - javascript

What we want to do is to use a single schema create a new array (with the values of arrObj:
const arrObj = [{
id: 1,
title: 'aaa'
}, {
id: 2,
title: 'bbb',
}]
const schema = [{
name: 'id',
value: ''
}, {
name: 'title',
value: ''
}]
const finalArrObj = []
arrObj.forEach(eachArrObj => {
const eachArr = [...schema] // copy array without pointing to the original one
eachArr.forEach(field => {
field.value = eachArrObj[field.name]
console.log('1: ' , field) // correct value
})
console.log('2: ', eachArr) // the objects are all the same
console.log('3: ', eachArr[0].value) // the object here is correct
finalArrObj.push(eachArr)
})
For some reason, the values in console log number 2 logs an array with the same object. Console log number 3 logs the correct object.
Why is this happening and how to fix it?
Live example: https://codepen.io/sky790312/pen/KmOgdy
UPDATE:
Desired result:
[{
name: 'id',
value: '1'
}, {
name: 'title',
value: 'aaa'
}],
[{
name: 'id',
value: '2'
}, {
name: 'title',
value: 'bbb'
}]

You could map new objects by using Object.assign for schema, before assigning values to it.
schema.map(a => Object.assign({}, a, { value: o[a.name] }))
^^^^^^^^^^^^^^^^ take empty object for
^ assingning values of a and
^^^^^^^^^^^^^^^^^^^^ only the value of a property
const arrObj = [{ id: 1, title: 'aaa' }, { id: 2, title: 'bbb' }],
schema = [{ name: 'id', value: '' }, { name: 'title', value: '' }],
finalArrObj = arrObj.map(o =>
schema.map(a => Object.assign({}, a, { value: o[a.name] }))
);
console.log(finalArrObj);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You have to copy the inner object also, replace this
const eachArr = [...schema];
with this
const eachArr = schema.map((e)=>{
return Object.assign({}, e);
})

Related

Filter JSON with desired keys

I have an array of objects sample for example :
const data = [
{
Name: 'test_1',
Value: '175',
Description: 'desc_1'
},
{
Name: 'test_2',
Value: '175',
Description: 'desc_2'
}
]
And an env file where I mark the data I want :
Name=true
Value=true
Description=false
How do I filter out the data file to only return the values of the keys Name and Value?
Desired output :
[
{
Name: 'test_1',
Value: '175'
},
{
Name: 'test_2',
Value: '175',
}
]
There are different ways in order to achieve the required output, here I'm making use of Array.map and Array.reduce methods.
const data = [{ Name: 'test_1', Value: '175', Description: 'desc_1', }, {Name: 'test_2', Value: '176', Description: 'desc_2', }];
//In order to access from the env file
/*
const fields = {
Name: process.env.Name,
Value: process.env.Value,
Description: process.env.Description
}
*/
//For the snippet purpose i'm using this hardcoded values
const fields = {
Name: true,
Value: true,
Description: false
}
//Convert the object to an array of keys whose values are needed from the original data
const getConfigData = fields => Object.keys(fields).filter(key => fields[key])
let config = getConfigData(fields);
const getSelectedKeyValues = (data, config) => {
return data.map(obj => config.reduce((acc, c) => (acc[c] = obj[c], acc), {}));
}
console.log("Name & Value:", getSelectedKeyValues(data, config));
.as-console-wrapper {
max-height: 100% !important;
}
You can do it like this:
const data = [
{ Name: 'test_1', Value: '175', Description: 'desc_1' },
{ Name: 'test_2', Value: '175', Description: 'desc_2' }
]
let results = data.map((item) => {
new_item = {};
if (process.env.Name) new_item.Name = item.Name;
if (process.env.Value) new_item.Value= item.Value;
if (process.env.Description) new_item.Description= item.Description;
return new_item;
})
Since your example is a JS array and no JSON string, you can use map:
const result = data.map(d => { return {Name: d.name, Value: d.Value }});
Another solution would be filtering the objects entries when mapping and creating a new object from those entries.
const data = [{
Name: 'test_1',
Value: '175',
Description: 'desc_1'
},
{
Name: 'test_2',
Value: '175',
Description: 'desc_2'
}
]
const status = {
Name: true,
Value: true,
Description: false
}
// props you want to keep
const keep = Object.keys(status).filter((k) => status[k]);
const result = data.map((d) => {
// create object from entries based on what you want to keep
return Object.fromEntries(Object.entries(d).filter(([k]) => {
return keep.includes(k)
}));
})
console.log(result);

How to filter an array in ReactJs by comparing it with another array

I have two arrays in ReactJS as follows
let document = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' }
]
let filterTypes = [{ value: 'abcd', id: 1 }]
How to generate the filtered array from this in ReactJS containing just one object with value abcd?
You could use Array.prototype.some() method inside Array.prototype.filter() method. Some method returns a Boolean value if at least one item in the array
passes the test by the given callback function.
const doc = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' },
];
const filterTypes = [{ value: 'abcd', id: 1 }];
const ret = doc.filter((x) => filterTypes.some((y) => y.value === x.value));
console.log(ret);
const docArray = [
{ text: 'Document 1', value: 'abcd' },
{ text: 'Document 2', value: 'efgh' },
];
const filterTypes = [{ value: 'abcd', id: 1 }];
console.log('-----non-matched----');
const nonmatched = docArray.filter(doc => filterTypes.findIndex(filt=> filt.value === doc.value));
console.log(nonmatched);
console.log('------matched----');
const matched = docArray.filter(doc => filterTypes.findIndex(filt=> filt.value !== doc.value));
console.log(matched);

How to loop through array of objects and make key value pairs?

I have an array of objects like this:
let someObj = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
I want add this to an exiting object, where id is a key of this object, like this:
let obj = {
someKey: someValue,
'12': true,
'34': true,
'56': false,
}
You may achieve your goal using Array#reduce as follows:
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = input.items.reduce((o, {
id,
value
}) => (o[id] = value, o), {})
console.log(output)
Also, and maybe the simplest approach might be using Array#map to turn objects into pairs and then convert them into an object using Object.fromPairs:
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = Object.fromEntries(input.items.map(({
id,
value
}) => [id, value]))
console.log(output)
Finally, here's a functional approach:
// Composes two functions
const compose = f => g => x => f (g (x))
// Given the key-value pairs of some object with 2 properties, maps a pair of values
const values = ([[, x], [, y]]) => [x, y]
// Turns an object of two properties into a pair of property values
const entry = compose (values) (Object.entries)
// Turns many objects of two properties, into an object on which
// keys are first properties' values, and vaules the second properties' values.
const keyValueObject = xs => Object.fromEntries (xs.map (entry))
const input = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const output = keyValueObject (input.items)
console.log(output)
You can iterate each item from items and create a new object as shown below.
let someObj = {
items: [{
id: '12',
value: true
}, {
id: '34',
value: true
}, {
id: '56',
value: false
}]
}
const newObj = {};
someObj.items.map(item =>{
newObj[item.id]= item.value;
});
console.log(newObj);
Use map and Object.values will simplify.
const output = arr => Object.fromEntries(arr.map(Object.values));
let someObj = {
items: [
{
id: "12",
value: true,
},
{
id: "34",
value: true,
},
{
id: "56",
value: false,
},
],
};
console.log(output(someObj.items));
First, you can transform the itens into "KV" entries
> someObj.items.map(({id, value}) => [id, value])
[ [ '12', true ], [ '34', true ], [ '56', false ] ]
Then turn it into Object
> Object.fromEntries(someObj.items.map(({id, value}) => [id, value]))
{ '12': true, '34': true, '56': false }
You can do a function
> let ObjectFromMapping = (vs, mapping) => Object.fromEntries(vs.map(mapping))
> ObjectFromMapping(someObj.items, ({id, value}) => [id, value])
{ '12': true, '34': true, '56': false }
Maybe turn vs into a iterable is a good idea
> let ObjectFromMapping = (vs, mapping) => Object.fromEntries([... vs].map(mapping))
> ObjectFromMapping("abc", (char, idx) => [idx, char])
{ '0': 'a', '1': 'b', '2': 'c' }
Then your function will work on any iterable

Compare two arrays and connect it

I have two arrays as types and defaultTypes. I need to display types with default values array defaultTypes.
const types = [
{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
const defaultTypes = [
{
Id: 1,
Name: 'Default value 1'
},
{
Id: 2,
Name: 'Default value 2'
}
]
If in types does not exist some of default types (in this case Id: 1 does not exist in the types array). I need to add that object in types array.
Expected result will be:
const expectedTypes = [
{
Id: 1,
Name: '-'
},
{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
Objects with Ids 1 and 2 always need to be in expectedTypes.
const expectedTypes = types.concat(
defaultTypes.filter(
type => !types.some(t => t.Id == type.Id)
));
explanation: basically what you want is types + stuff in defaultTypes that are not in types already.
Try this one:
let types = [{
Id: 2,
Name: 'Some value here'
},
{
Id: 3,
Name: 'Some value here'
},
{
Id: 4,
Name: 'Some value here'
}
];
const defaultTypes = [{
Id: 1,
Name: 'Default value 1'
},
{
Id: 2,
Name: 'Default value 2'
}
];
defaultTypes.forEach(dt => {
if (!types.some(t => t.Id === dt.Id)) {
types.push(dt);
}
});
types = types.sort((a, b) => a.Id - b.Id);
console.log(types);
Use this code and try
var _ = require('lodash');
defaultTypes.forEach(type => {
if (!_.find(types, { Id: type.Id })) {
types.push({ Id: type.Id, Name: '-' });
}
});
You can first use create a Set using map() which will contain its of elements in types.
Then loop through the defaultTypes and check if the Set contain the Id. If doesn't then push() it to types
At the end use sort() to order the elements by Id
const types = [ { Id: 2, Name: 'Some value here' }, { Id: 3, Name: 'Some value here' }, { Id: 4, Name: 'Some value here' } ];
const defaultTypes = [ { Id: 1, Name: 'Default value 1' }, { Id: 2, Name: 'Default value 2' } ]
let ids = new Set(types.map(x => x.Id));
defaultTypes.forEach(x => {
if(!ids.has(x.Id)) types.push(x)
})
types.sort((a,b) => a.Id - b.Id)
console.log(types)
Purpose Of Set
The purpose of Set is to make the time complexity liner O(n). If you don't use Set you will need to use some() on the types in each loop. So the time-complexity would be O(m*n)
Set.prototype.has has time complexity O(1)
You could reduce the elements in the wanted order with a Map and get all values as result.
const
types = [{ Id: 2, Name: 'Some value here' }, { Id: 3, Name: 'Some value here' }, { Id: 4, Name: 'Some value here' }],
defaultTypes = [{ Id: 1, Name: 'Default value 1' }, { Id: 2, Name: 'Default value 2' }],
result = Array.from([...defaultTypes, ...types]
.reduce((m, o) => m.set(o.Id, Object.assign({}, m.get(o.Id), o)), new Map)
.values()
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Transform a object into a new object object.assign

I have 2 objects:
const refer = [
{ key: 'A.ABC', value: 'ABC', display: 'ABC' },
{ key: 'A.PQR', value: 'INFOPQR', display: 'PQR' },
{ key: 'Q', value: 'Q', display: 'Q'},
]
const mapObj = [
{id: "A.ABC", name: "other value"},
{id: "A.PQR", name: "some values"},
]
I want to return a new object by applying a transform layer to mapObject that is basically like:
[
{id: "A.ABC", name: "other value"},
{id: "INFOPQR", name: "some values"},
]
notice that the value from refer object should be the id in mapObj only if the key of refer matches to id of mapobj.
const transform = refer => {
refer.map(r => {
const f = mapObj.filter(d => d.id === r.id);
});
}
I have the above so far. How do I use Object.assign to actually transform.
You can do this with map() and find() methods, and if key matches id from object in other array you can use Object.assign() to return new object else return current object.
const refer = [
{ key: 'A.ABC', value: 'ABC', display: 'ABC' },
{ key: 'A.PQR', value: 'INFOPQR', display: 'PQR' },
{ key: 'Q', value: 'Q', display: 'Q'},
]
const mapObj = [
{id: "A.ABC", name: "other value"},
{id: "A.PQR", name: "some values"},
]
const result = mapObj.map(o => {
const ref = refer.find(e => e.key == o.id)
return !ref ? o : Object.assign({}, o, {id: ref.value})
})
console.log(result)

Categories