Formatting a new array with existing data - problem - javascript

I am trying to make a new array from the data object that I have which looks like this:
const data= {
periods: [{
month: 'January',
types: [
{
name: 'sick leave',
difference: '14',
revisioned: '7000',
paid: '5000',
},
{
name: 'holiday',
difference: '12',
revisioned: '4000',
paid: '6000',
},
],
received: '3000',
taken: '2000',
result: '0',
},
{
month: 'February',
types: [
{
name: 'sick leave',
difference: '5',
revisioned: '100',
paid: '200',
},
{
name: 'holiday',
difference: '4',
revisioned: '300',
paid: '232',
},
],
received: '-2000',
taken: '2000',
result: '0',
}],
};
What I would like to do is, to take that object and take the properties types, received, taken and result and from each of these properties values create an array that would be a property of an object in a new array. The end result of the new array would look something like this:
[
{
name: 'sick_leave_difference',
result: ['14', '5'],
},
{
name: 'sick_leave_revisioned',
result: ['7000', '100'],
},
{
name: 'sick_leave_paid',
resultat: '[5000, 200]',
},
{
name: 'holiday_difference',
resultat: ['12', '4'],
},
{
name: 'holiday_revisioned',
result: ['4000', '300'],
},
{
name: 'holiday_paid',
result: '[6000, 232]',
},
{
name: 'received',
resultat: ['3000', '-2000'],
},
{
navn: 'taken',
result: ['2000', '2000'],
},
{
name: 'result',
result: ['0', '0'],
},
];
The problem is that the propery types contains an array and it is different is different from the other properties, so I am not sure how to achieve this and also in an elegant way?

Use Array.reduce() to extract and flatten the types array. Reduce the flattened array, and iterate the each object's entries with Array.forEach(). Create the result object if it doesn't exists, and add the results. Extract back to array using Object.values():
const data= {"periods":[{"month":"January","types":[{"name":"sick leave","difference":"14","revisioned":"7000","paid":"5000"},{"name":"holiday","difference":"12","revisioned":"4000","paid":"6000"}],"received":"3000","taken":"2000","result":"0"},{"month":"February","types":[{"name":"sick leave","difference":"5","revisioned":"100","paid":"200"},{"name":"holiday","difference":"4","revisioned":"300","paid":"232"}],"received":"-2000","taken":"2000","result":"0"}]};
const result = Object.values(data.periods
.reduce((r, { types }) => [...r, ...types], [])
.reduce((r, { name, ...props }) => {
Object.entries(props).forEach(([k, v]) => {
const navn = `${name} ${k}`.replace(' ', '-');
if(!r[navn]) r[navn] = { navn, result: [] };
r[navn].result.push(v);
});
return r;
}, {}));
console.log(result);

Related

How to merge two different array of object in JavaScript? Check below example

Input Arrays:
var array1 = [
{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
},
];
var array2 = [
{
uniqueId: '111'
},
{
uniqueId: '222'
},
];
Result:
var results = [
{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something',
uniqueId: '111'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever',
uniqueId: '222'
},
];
There are a few ways to do this, perhaps this is acceptable? Simply looping over the first array and using the index to select the correct object from the second array.
var array1 = [
{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
},
];
var array2 = [
{
uniqueId: '111'
},
{
uniqueId: '222'
},
];
var result = [];
array1.forEach((itm, idx, _) => {
result.push({ ...itm, ...array2[idx] });
});
console.log(result)
You can use Array.map() along with spread syntax (...) to merge the values from the two arrays.
const array1 = [ { PersonalID: '11', qusetionNumber: '1', value: 'Something' }, { PersonalID: '12', qusetionNumber: '2', value: 'whatever' }, ];
const array2 = [ { uniqueId: '111' }, { uniqueId: '222' }, ];
const result = array1.map((el, idx) => ({ ...el, ...array2[idx]}));
console.log('Result:', result)
.as-console-wrapper { max-height: 100% !important; }
In addition to the already provided approaches one also could implement callback functions for ...
a map based approach where the callback utilizes the map methods 2nd thisArg parameter for providing the 2nd array (the OP's array2).
a reduce based approach where the callback gets the 2nd array (the OP's array2) provided as property of the reduce methods 2nd parameter, its initial value.
In both cases Object.assign is one possible way of creating a merged object which is loosely decoupled from both of its source items.
Unlike all the other so far provided solutions both suggested ways have in common that each implementation is agnostic to the OP's outer-scope array-references. And due to being provided as function statements the code is re-usable as well.
const array1 = [{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
}, {
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
}];
const array2 = [{
uniqueId: '111'
}, {
uniqueId: '222'
}];
function mergeWithBoundArraysRelatedItem(item, idx) {
return Object.assign({}, item, this[idx]);
}
console.log(
'`map` based ...\n\n',
'array1.map(mergeWithBoundArraysRelatedItem, array2) =>',
array1
.map(mergeWithBoundArraysRelatedItem, array2)
);
function mergeRelatedArrayItems({ result, source }, item, idx) {
result.push(
Object.assign({}, item, source[idx])
);
return { result, source };
}
console.log(
'`reduce` based ...\n\n',
'array1.reduce(mergeRelatedArrayItems, { source: array2, result: [] }).result =>',
array1
.reduce(mergeRelatedArrayItems, {
source: array2, result: [],
})
.result
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
var array1 = [
{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
},
];
var array2 = [
{
uniqueId: '111'
},
{
uniqueId: '222'
},
];
const fun =(ar , ar2)=>{
for(let [k , v] of Object.entries(ar2)){
for(x in v){
ar[k][x] = v[x]
}
}
return ar
}
console.log(fun(array1 , array2))
var array1 = [
{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
},
];
var array2 = [
{
uniqueId: '111'
},
{
uniqueId: '222'
},
];
// if you don't want array1 to be modified use instead
// Array.from(array1).map(function(e,i){return Object.assign(e,array2[i])})
array1.map(function(e,i){return Object.assign(e,array2[i])})
console.log(array1)
I can also use Object.assign
var array1 = [{
PersonalID: '11',
qusetionNumber: '1',
value: 'Something'
},
{
PersonalID: '12',
qusetionNumber: '2',
value: 'whatever'
},
];
var array2 = [{
uniqueId: '111'
},
{
uniqueId: '222'
},
];
let myArr = []
for(let i = 0 ; i<array1.length ; i++){
myArr.push(Object.assign(array1[i], array2[i]))
}
console.log(myArr)

How to return the data in one function call for two different object keys

I have an object which looks like this :
const data = {
students: [{
code: '1',
number: '22',
type: 'regular',
name: 'john',
age: '11',
class: 'A',
}, {
code: '2',
number: '23',
type: 'regular',
name: 'steve',
age: '12',
class: 'B',
}],
teachers: [{
code: '22',
number: '101',
type: 'intern',
name: 'mac',
}, {
code: '23',
number: '102',
type: 'perm',
name: 'jess',
}],
};
It has different keys and values.
Here, I am trying to massage this data so that I can obtain the following result: So I am trying to get an array which will have only students data and other which will have teachers data from one function itself.
const result1 = [{
code: '1',
number: '22',
type: 'regular',
name: 'john',
}, {
code: '2',
number: '23',
type: 'regular',
name: 'steve',
}];
const result2 = [{
code: '22',
number: '101',
type: 'intern',
name: 'mac',
}, {
code: '23',
number: '102',
type: 'perm',
name: 'jess',
}];
what I tried is :
const getData = ({data = []}) => {
data?.map({ code,
number,
regular,
name } ) => {
return{
code,
number,
regular,
name
}}
}
getData(data.students)
getData(data.teachers) // How do get this data in one function call itself
This gives me the result , but for this I need to call this function twice once for students and one for teachers. I want to call this function once.
Thanks
You could map new entries from the object and take the mapped new structure.
const
data = { students: [{ code: '1', number: '22', type: 'regular', name: 'john', age: '11', class: 'A' }, { code: '2', number: '23', type: 'regular', name: 'steve', age: '12', class: 'B' }], teachers: [{ code: '22', number: '101', type: 'intern', name: 'mac' }, { code: '23', number: '102', type: 'perm', name: 'jess' }] },
getData = ({ code, number, regular, name }) => ({ code, number, regular, name }),
result = Object.fromEntries(Object
.entries(data)
.map(([k, v]) => [k, v.map(getData)])
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Since from the provided data, it looks like the OP wants to mainly map a certain set of properties of student/teacher items from a map/object, a possible approach is to reduce the data object's entries and apply the mapping exclusively for a matching students or teachers key each referring to a valid array-type value.
const data = {
students: [{ code: "1", number: "22", type: "regular", name: "john", age: "11", class: "A" }, { code: "2", number: "23", type: "regular", name: "steve", age: "12", class: "B" }],
teachers: [{ code: "22", number: "101", type: "intern", name: "mac" }, { code: "23", number: "102", type: "perm", name: "jess" }],
};
const {
students: result1,
teachers: result2,
} = Object
.entries(data)
.reduce((result, [key, value]) => {
if (
// process only for a matching key ...
(/^students|teachers$/).test(key)
// ... and a valid value type.
&& Array.isArray(value)
) {
result[key] = value
.map(({ code, number, type, name }) =>
({ code, number, type, name })
);
}
return result
}, {});
console.log({ result1, result2 });
.as-console-wrapper { min-height: 100%!important; top: 0; }
I'm not sure what use there is in this, but since you want to run a function twice and get two results, do that, and combine into an object:
const data = {
students: [{
code: '1',
number: '22',
type: 'regular',
name: 'john',
age: '11',
class: 'A'
}, {
code: '2',
number: '23',
type: 'regular',
name: 'steve',
age: '12',
class: 'B'
}],
teachers: [{
code: '22',
number: '101',
type: 'intern',
name: 'mac'
}, {
code: '23',
number: '102',
type: 'perm',
name: 'jess'
}]
};
const transformData = (data = []) =>
data.map(({
code,
number,
regular,
name
}) => ({
code,
number,
regular,
name
}));
const getData = (data) =>
({
students: transformData(data.students),
teachers: transformData(data.teachers)
});
console.log(getData(data));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Note: I modified the transformData function to remove some extra syntax, and to remove the optional chaining since the Stack Snippets' ancient version of Babel doesn't support it.
Also, there's no property named regular on the original objects in the array, so they come out undefined.
Based on the input and output looks like you're just trying to slice off the keys age and class from the objects. So you'd just need to iterate through both the keys then the underlying objects to remove them.
const getData = (data) => {
Object.keys(data).forEach(function callback(key) {
let value = data[key];
value.forEach(function callback(obj) {
let blockArray = ['age', 'class'];
blockArray.forEach(e => delete obj[e]);
});
});
return data;
}
const updatedData = getData(data);
const result1 = updatedData.students;
console.dir(result1);
const result2 = updatedData.teachers;
console.dir(result2);

How to loop over a an array that is already inside a map function without duplicating the contents

I have the following code with the following arrays. I want to loop through both of them and pull out some data, and put them inside a final array. I am able to do that, but the contents are duplicated. I tried reading about reduce but don't quite understand it, and am not sure if it's the right solution. I have also setup a jsfiddle
https://jsfiddle.net/anders_kitson/Lcqn6fgd/
var lineItems = [{
id: 'li_1HyhAZHk5l44uIELgsMWqHqB',
object: 'item',
amount_subtotal: 7500,
amount_total: 7500,
currency: 'cad',
description: 'The Spencer',
price: [Object],
quantity: 1
},
{
id: 'li_1HyhAZHk5l44uIELeNUsiZPu',
object: 'item',
amount_subtotal: 7500,
amount_total: 7500,
currency: 'cad',
description: 'The Gertie',
price: [Object],
quantity: 1
}
]
var arr = [{
id: 'prod_IS1wY1JvSv2CJg',
object: 'product',
active: true,
attributes: [],
created: 1606248785,
description: 'Shelf Set',
images: [
'https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq'
],
livemode: false,
metadata: {},
name: 'The Spencer',
statement_descriptor: null,
type: 'service',
unit_label: null,
updated: 1606248785
},
{
id: 'prod_IS299dMnC13Ezo',
object: 'product',
active: true,
attributes: [],
created: 1606249543,
description: 'Shelf Set',
images: [
'https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe'
],
livemode: false,
metadata: {},
name: 'The Gertie',
statement_descriptor: null,
type: 'service',
unit_label: null,
updated: 1606249543
}
];
let productArr = [];
arr.map((item) => {
lineItems.map((line) => {
productArr.push({
image: item.images[0],
name: item.name,
price: line.amount_total,
});
});
});
console.log(productArr);
This is the output I get where you can see the array repeats the values, and I know I have coded it this way I just don't know how to fix it.
[{
image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
name: "The Spencer",
price: 7500
}, {
image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
name: "The Spencer",
price: 7500
}, {
image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
name: "The Gertie",
price: 7500
}, {
image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
name: "The Gertie",
price: 7500
}]
To Be more clear this is the output that I want
[{
image: "https://files.stripe.com/links/fl_test_raNEqk9ZhzX3WdQsnvXX4gFq",
name: "The Spencer",
price: 7500
}, {
image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
name: "The Gertie",
price: 7500
},
]
I have tried the suggestion in the comments with the following
let b
arr.map((item) => {
b = lineItems.map((line) => {
return {
image: item.images[0],
name: item.name,
price: line.amount_total,
};
});
});
but it returns the same ones twice
[{
image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
name: "The Gertie",
price: 7500
}, {
image: "https://files.stripe.com/links/fl_test_QPbrP76uNn4QadgcUwUnkmbe",
name: "The Gertie",
price: 7500
}]
Although not expressed directly in your question, it seems you're looking to do a join in javascript. The only things I see relating the two are 'name' in products and 'description' in the line items. So do a loop join on that.
Here's some sample code using your example but stripped down only to what's relevant:
var lineItems = [
{ amount_total: 7500, description: 'The Spencer' },
{ amount_total: 7500, description: 'The Gertie' }
]
var arr = [
{ images: ['Spencer Image 1'], name: 'The Spencer' },
{ images: ['Gertie Image 1'], name: 'The Gertie' }
]
let joined = arr
.flatMap(a => lineItems.map(li => ({a, li})))
.filter(obj => obj.a.name == obj.li.description)
.map(obj => ({
image: obj.a.images[0],
name: obj.a.name,
price: obj.li.amount_total
}));
console.log(joined);
Being a loop join, it may not be that efficient. To do a hash join is a little more involved. You can look through the source code of my developing project
fluent-data, or it might even be useful to you to use it directly if you can follow the documentation.
You can use a single map call and reference your second lineItems array either by index, if you know that the two arrays are the same length and order
const output = arr.map((o, i) => ({
name: o.name,
image: o.images[0],
price: lineItems[i].amount_total}
));
or by using find() to retrieve the relevant object.
const outputUsingFind = arr.map(o => {
const lineItem = lineItems.find(item => item.description === o.name);
// ** add lineItem valid check here **
return {
name: o.name,
image: o.images[0],
price: lineItem.amount_total};
});
var lineItems = [{amount_subtotal: 7500,amount_total: 700,description: 'The Spencer',},{amount_subtotal: 7500,amount_total: 500,description: 'The Gertie',}];
var arr = [{images: ['spencer image'],name: 'The Spencer',},{images: ['gertie image'],name: 'The Gertie'}];
// since your arrays are ordered the same you can access the second object using
// the index passed from map.
const output = arr.map((o, i) => ({
name: o.name,
image: o.images[0],
price: lineItems[i].amount_total}
));
console.log(output);
// if the two arrays are not in the same order you can use find() to retrieve
// the second object by property (you'll need to check
const outputUsingFind = arr.map(o => {
const lineItem = lineItems.find(item => item.description === o.name);
// ** add lineItem valid check here **
return {
name: o.name,
image: o.images[0],
price: lineItem.amount_total};
});
console.log(outputUsingFind);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Merge arrays to one array after filtering

I've got array of objects, where I take only locations array. My goal is to merge these locations array to one array, however I fail to do so and get empty array. This is how I do it:
let results = [{
id: '1',
locations: ['aaaa', 'bbbbbb', 'cccccc']
},
{
id: '2',
locations: []
},
{
id: '3',
locations: ['ddd', 'aaadsad', 'sefd']
},
{
id: '4',
locations: ['ffff', 'eeee', 'sfdsfsd']
},
];
const locationIds = [].concat.apply([], ...results.filter(s => s.locations && s.locations.length > 0).map(({
locations
}) => ({
locations
})));
console.log(locationIds);
what I am doing wrong here? The result should be
['aaaa', 'bbbbbb', 'cccccc', 'ddd', 'aaadsad', 'sefd', 'ffff', 'eeee', 'sfdsfsd'];
You don't need filter here. Just use map method by passing a callback provided function which is applied for every item on the array.
let results = [{ id: '1', locations: ['aaaa', 'bbbbbb', 'cccccc'] }, { id: '2', locations: [] }, { id: '3', locations: ['ddd', 'aaadsad', 'sefd'] }, { id: '4', locations: ['ffff', 'eeee', 'sfdsfsd'] }, ];
const locationIds = [].concat(...results.map(s => s.locations));
console.log(locationIds);
You can try with flatMap():
The flatMap() method first maps each element using a mapping function, then flattens the result into a new array. It is identical to a map() followed by a flat() of depth 1, but flatMap() is often quite useful, as merging both into one method is slightly more efficient.
let results = [{
id: '1',
locations: ['aaaa', 'bbbbbb', 'cccccc']
},
{
id: '2',
locations: []
},
{
id: '3',
locations: ['ddd', 'aaadsad', 'sefd']
},
{
id: '4',
locations: ['ffff', 'eeee', 'sfdsfsd']
},
];
const locationIds = results.flatMap(i => i.locations);
console.log(locationIds);
You could taka a Array#flatMap with the wanted property. If the property is not given, add a default array || [].
let results = [{ id: '1', locations: ['aaaa', 'bbbbbb', 'cccccc'] }, { id: '2', locations: [] }, { id: '3', locations: ['ddd', 'aaadsad', 'sefd'] }, { id: '4', locations: ['ffff', 'eeee', 'sfdsfsd'] }],
locationIds = results.flatMap(({ locations }) => locations);
console.log(locationIds);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Can also solve using the Reduce function from Array.prototype.
var newResults = results.reduce(function(acc, curr) {
return acc.concat(curr.locations)
},[]
)
hope this helps
I spent too long on this not to post my own solution - interesting puzzle for me, although the other answers are no doubt more performant and readable. It uses the same sort of strategy as your original post, which might help point out where it went wrong.
const locationIds = [].concat
.apply([], results.filter(result =>
result.locations && result.locations.length > 0)
.map(result => { return result.locations }));

how convert array to object with specific key in javascript

I have a big array with below format
[
{
id: '1',
name: "bloh",
coordinates: [[51.3888562, 35.7474398], [51.388671,35.7470575],[51.3887346, 35.7470375]]
},
{
id: '2',
name: "blohbloh",
coordinates: [[51.3888562, 35.7474398],[51.3822271, 35.7444575]]
}
]
I want to convert format of coordinates property of all elements to below format
{
id: '1',
name: "bloh",
coordinates:[{longitude:51.3888562,latitude: 35.7474398},{longitude:51.3887346,latitude: 35.7470375}]
},
{
id: '2',
name: "blohbloh",
coordinates:[{longitude:51.3888562,latitude: 35.7474398},{longitude:51.3822271,latitude: 35.7444575}]
}
You should be able to do this with map:
let input = [{id: '1', name: "bloh", coordinates: [[51.3888562, 35.7474398], [51.388671,35.7470575],[51.3887346, 35.7470375]]},{id: '2', name: "blohbloh",coordinates: [[51.3888562, 35.7474398],[51.3822271, 35.7444575]]}];
let result = input.map(({id, name, coordinates}) => {
return { id, name, coordinates: coordinates.map(([latitude,longitude]) => { return { latitude, longitude}})};
});
console.log("Result: ", result);
You can loop through the array and then you need to use map to change representation of coordinates from array to object.
You can use following code to convert.
var arr=[{id: '1', name: "bloh", coordinates: [[51.3888562, 35.7474398], [51.388671,35.7470575],[51.3887346, 35.7470375]]},{id: '2', name: "blohbloh",coordinates: [ [51.3888562, 35.7474398],[51.3822271, 35.7444575]]}];
arr.forEach(elm=>elm.coordinates=elm.coordinates.map(c=>({longitude:c[0],latitude:c[1]})));
console.log(arr);
You can use two map() and destructuring to copy all properties of the top-level objects in a rest variable and map() the coordinates to another format:
const data = [{id: '1', name: "bloh", coordinates:[[51.3888562, 35.7474398], [51.388671,35.7470575],[51.3887346, 35.7470375]]},{id: '2', name: "blohbloh",coordinates:[[51.3888562, 35.7474398],[51.3822271, 35.7444575]]}];
const result = data.map(({ coordinates, ...rest }) =>
({
...rest,
coordinates: coordinates.map(([longitude, latitude]) => ({ longitude, latitude }))
})
);
console.log(result);
In any kind of problem you face, first, you should understand what you need to do, and prettier data will always help you to achieve this.
You want to convert this:
const original = [{
id: '1',
name: "bloh",
coordinates: [ [51.3888562, 35.7474398],
[51.388671,35.7470575],
[51.3887346, 35.7470375] ]
},
{
id: '2',
name: "blohbloh",
coordinates: [ [51.3888562, 35.7474398],
[51.3822271, 35.7444575] ]
}
]
To this:
{
id: '1',
name: "bloh",
coordinates:[
{longitude:51.3888562,latitude: 35.7474398},
{longitude:51.3887346,latitude: 35.7470375}
]
},
{
id: '2',
name: "blohbloh",
coordinates:[
{longitude:51.3888562,latitude: 35.7474398},
{longitude:51.3822271,latitude: 35.7444575}
]
}
We will use the 'for' loop because it is easier to see what's going on, in my own opinion.
for(i in original){
original[i].coordinates = original[i].coordinates.map(item => {return {
latitude: item[0],
longitude: item[1]}
})
}
console.log(JSON.stringify(original))
You can use prettifier to see your data in more pretty way,for example using this resource: https://jsonformatter.curiousconcept.com/
Hope this will help.

Categories

Resources