i wanted to move element in nested array. so, here this my data:
let products = [
{
"product_name": "A",
"_id": "5ace995c14a759325776aab1",
"transactions": [
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 100,
"price": 2000
},
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 80,
"price": 1500
},
]
},
{
"product_name": "B",
"_id": "5ace995914a759325776aab0",
"transactions": [
{
"_id": "5ad3a274ac827c165a510f9b",
"qty": 80,
"price": 1500
}
],
}
]
The output that i expected:
[
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 100,
"price": 2000,
"product_name": "A",
},
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 80,
"price": 1500,
"product_name": "A",
},
{
"_id": "5ad3a274ac827c165a510f9b",
"qty": 80,
"price": 1500,
"product_name": "B",
}
]
then, my solve code:
function move() {
var result = []
for (product of products) {
for (transaction of product.transactions) {
transaction.product_name = product.product_name
result.push(transaction)
}
}
return result
}
product = move()
Is there any effective way to create the output, maybe with array map or anything else? Thank you.
You could flat the transactions with Array#reduce and using Object.assign for adding product_name.
Also used:
destructuring assignment for the properties and
short hand properties for taking a variable as property with the name as key.
var products = [{ product_name: "A", _id: "5ace995c14a759325776aab1", transactions: [{ _id: "5ad3a274ac827c165a510f99", qty: 100, price: 2000 }, { _id: "5ad3a274ac827c165a510f99", qty: 80, price: 1500 }] }, { product_name: "B", _id: "5ace995914a759325776aab0", transactions: [{ _id: "5ad3a274ac827c165a510f9b", qty: 80, price: 1500 }] }],
result = products.reduce((r, { transactions, product_name }) =>
r.concat(transactions.map(t => Object.assign({}, t, { product_name }))),
[]
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can reduce and map the transactions to add the product name
let result = products.reduce((c,v)=>{ //Loop the array using reduce
let transactions = v.transactions.map(o=>{ //Loop thru each transactions using map
return Object.assign(o,{"product_name":v.product_name}); //Clone the transaction and add the property product_name
});
return c.concat(transactions); //Merge the current array and the transactions
},[]);
Here is a snippet:
//Your array
let products=[{"product_name":"A","_id":"5ace995c14a759325776aab1","transactions":[{"_id":"5ad3a274ac827c165a510f99","qty":100,"price":2000},{"_id":"5ad3a274ac827c165a510f99","qty":80,"price":1500},]},{"product_name":"B","_id":"5ace995914a759325776aab0","transactions":[{"_id":"5ad3a274ac827c165a510f9b","qty":80,"price":1500}],}]
//The short version
let result = products.reduce((c, v) => c.concat(v.transactions.map(o =>Object.assign(o, {"product_name": v.product_name}))), []);
console.log(result);
Just using js methods you can have your desired output
const products = [
{
"product_name": "A",
"_id": "5ace995c14a759325776aab1",
"transactions": [
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 100,
"price": 2000
},
{
"_id": "5ad3a274ac827c165a510f99",
"qty": 80,
"price": 1500
},
]
},
{
"product_name": "B",
"_id": "5ace995914a759325776aab0",
"transactions": [
{
"_id": "5ad3a274ac827c165a510f9b",
"qty": 80,
"price": 1500
}
],
}
]
let output =[];
products.forEach(elm => elm.transactions.forEach(transaction => {
transaction.product_name = elm.product_name;
output.push(transaction)}));
console.log(output);
Related
I'm developing an app in reactjs and I have the array:
array = [
{
"id": 1,
"categoryId": 2,
"period": "202101",
"type": "A",
"price": 100,
"discount": 0
},
{
"id": 2,
"categoryId": 2,
"period": "202102",
"type": "B",
"price": 300,
"discount": 20
},
{
"id": 3,
"categoryId": 2,
"period": "202103",
"type": "B",
"price": 200,
"discount": 70
},
{
"id": 4,
"categoryId": 2,
"period": "202104",
"type": "A",
"price": 100,
"discount": 50
},
]
and I need to reduce it to show it as the table:
what I did to show the detail of the prices per period:
const items = array.reduce((acc, e) => {
if (!acc[e["categoryId"]]) {
acc[e["categoryId"]] = {
[e["period"]]: e["price"]
}
} else {
acc[e["categoryId"]][e["period"]] = e["price"]
}
return acc
}, {})
const periods = [...new Set(Object.keys(items).map(i => Object.keys(items[i])).flat())]
thead:
<tr>{dates.map(date => <th>{date}</th>)}</tr>
tbody:
Object.keys(items).map((item) => {
return (
<tr>
<td>{item}</td>
{periods.map((period) => <td>{items[item][period] || ''}</td>)}
</tr>
)
})
but it is only showing the price for each period. I need to show discount and type as well.
What changes are needed, any suggestion?
I think I didn't understand your needs well,
but this is what I did according to your description:
array.reduce((acc, curr) => {
if (!acc[curr["categoryId"]]) {
acc[curr["categoryId"]] = {
[curr["period"]]: {
"price": curr["price"],
"type": curr["type"],
"discount": curr["discount"]
}
}
} else {
acc[curr["categoryId"]][curr["period"]] = {
"price": curr["price"],
"type": curr["type"],
"discount": curr["discount"]
}
}
return acc;
}, {})
And the result of this reduce is:
{
"2": {
"202101": {
"price": 100,
"type": "A",
"discount": 0
},
"202102": {
"price": 300,
"type": "B",
"discount": 20
},
"202103": {
"price": 200,
"type": "B",
"discount": 70
},
"202104": {
"price": 100,
"type": "A",
"discount": 50
}
}
}
what you are looking for is grouping the items in arrays and display them.:
let array = [
{
id: 1,
categoryId: 2,
period: "202101",
type: "A",
price: 100,
discount: 0
},
{
id: 2,
categoryId: 2,
period: "202102",
type: "B",
price: 300,
discount: 20
},
{
id: 3,
categoryId: 2,
period: "202103",
type: "B",
price: 200,
discount: 70
},
{
id: 4,
categoryId: 2,
period: "202104",
type: "A",
price: 100,
discount: 50
}
];
let dates = array.map((e) => <th>{e.period}</th>);
let prices = array.map((e) => <td>{e.price}</td>);
let discounts = array.map((e) => <td>{e.discount}</td>);
let types = array.map((e) => <td>{e.type}</td>);
function App() {
return (
<div className="App">
<table>
<tr>{dates}</tr>
<tr>{prices}</tr>
<tr>{discounts}</tr>
<tr>{types}</tr>
</table>
</div>
);
}
ReactDOM.render(<App/>,document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I have an array like this:
[
{
"costs": [{
"value": "80"
}],
"id": 4,
"name": "Subscription Fee",
"month": "March"
},
[
{
"costs": [{
"value": "200"
}],
"id": 2,
"name": "Tution",
"month": "March"
},
{
"costs": [{
"value": "10"
}],
"id": 11,
"name": "DEMO"
}
]
]
I need to have sumation of all the values from costs. How can i do that?
const data = [
{"costs":[{"value":"80"}],"id":4,"name":"Subscription Fee","month":"March"},
[
{"costs":[{"value":"200"}],"id":2,"name":"Tution","month":"March"},
{"costs":[{"value":"10"}],"id":11,"name":"DEMO"}
]
];
// flatten the arrays to get a list of objects
// iterate over this list
const res = data.flat().reduce((total, { costs = [] }) => {
// add the values of this item's costs with total
costs.forEach(({ value = 0 }) => total += +value);
return total;
}, 0);
console.log(res);
I have an array of objects. I want to group them by a specific field.
[
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
]
The output I expect for grouping by name attribute is as follows.
{
// Group #1
"JOHN": [
{
"type": 2,
"sum": 200
}
{
"type": 1,
"sum": 5
}
],
// Group #2
"SERA":[
{
"type": 1,
"sum": 43
},
{
"type": 2,
"sum": 129
},
]
}
I used nested loops, but unfortunately the execution speed was slow and it did not give the right results.
As if you mentioned, we can use an object instead of an array for the most outer wrapper. And also swap inside one object to an array, then this is a possible solution.
var data = [{"name": "JOHN","type": 1,"sum": 5},{"name": "SERA","type": 1,"sum": 43},{"name": "SERA","type": 2,"sum": 129},{"name": "JOHN","type": 2,"sum": 200}];
var newData = {};
data.forEach( (item) => {
if (!(item['name'] in newData)) {
newData[item['name']] = [];
}
newData[item['name']].push(
{
'type': item['type'],
'sum' : item['sum']
}
);
});
console.log(newData);
Your proposed output structure is not valid, however using Array.reduce you can create an object in which all the properties are arrays of objects:
const data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
const result = data.reduce((c, {name, type, sum}) => {
c[name] = c[name] || [];
c[name].push({type, sum});
return c;
}, {});
console.log(result);
One more way with forEach, destructuring and ?? operator
const merge = (arr) => {
const obj = {};
arr.forEach(({ name, ...rest }) => (obj[name] ??= []).push(rest));
return obj;
};
const data = [
{
name: "JOHN",
type: 1,
sum: 5,
},
{
name: "SERA",
type: 1,
sum: 43,
},
{
name: "SERA",
type: 2,
sum: 129,
},
{
name: "JOHN",
type: 2,
sum: 200,
},
];
console.log(merge(data));
You can use this function which take advantage of Array.prototype.reduce to transform the initial data to another structure of array.
let data = [
{
"name": "JOHN",
"type": 1,
"sum": 5
},
{
"name": "SERA",
"type": 1,
"sum": 43
},
{
"name": "SERA",
"type": 2,
"sum": 129
},
{
"name": "JOHN",
"type": 2,
"sum": 200
}
];
function groupedBy(data, field) {
let fieldValues = [...data].reduce((acc, current) => {
return acc.concat(current[field]);
}, []).filter((value, index, self) => {
return self.indexOf(value) === index;
});
let results = fieldValues.reduce((acc, item) => {
let items = [...data].filter(el => {
return el.name === item;
});
items.forEach(i => delete i.name);
return Object.assign(acc, { [item]: items});
}, {});
return results;
}
console.log(groupedBy(data, "name"));
I am working in small react project & I am facing issue in grouping the data. Requirement is to group the id & its feature into a single row if same id is there in before & after object.
Json Data:
{
"before":{
"device": [
{
id:"1234",
price:"10,
features:[
{name:"samsung",price:"10"},
{name:"Apple",price:"20"}
]
},
{id:"2154",
price:"20,
features:[
{name:"samsung",price:"30"},
{name:"Moto",price:"40"}
]
]
},
"after":{
"device": [
{
id:"1234",
price:"50,
features:[
{name:"samsung",price:"20"},
{name:"Lenovo",price:"30"}
]
},
{id:"2158",
price:"40,
features:[
{name:"samsung",price:"30"}
]
]
}
}
Expected grouping to be shown in UI is shared in image.
I tried to get unique ids in one array and lopping through after array and comparing unique array id I am getting unique id to show but issue i am facing while grouping their related feature.
Can anyone please help me to get a best approach to handle this requirement.
Thanks
There are 3 things i'd suggest you:
1.) Please verify the data your'e posting is correct and in proper format, people won't be able to help if the data is incorrect.
2.) The UI display requirement should be simple enough.
Now, if you still want to achieve this requirement i believe the correct JSON and the merged output json will look something like below:
//Correct input data that you have:
var input = {
"before": {
"device": [
{
"id": "1234",
"price": "10",
"features": [
{
"name": "samsung",
"price": "10"
},
{
"name": "Apple",
"price": "20"
}
]
},
{
"id": "2154",
"price": "20",
"features": [
{
"name": "samsung",
"price": "30"
},
{
"name": "Moto",
"price": "40"
}
]
}
]
},
"after": {
"device": [
{
"id": "1234",
"price": "50",
"features": [
{
"name": "samsung",
"price": "20"
},
{
"name": "Lenovo",
"price": "30"
}
]
},
{
"id": "2158",
"price": "40",
"features": [
{
"name": "samsung",
"price": "30"
}
]
}
]
}
};
// Output JSON which you should need to show the desired output.
var output = {
"devices": [
{
"id": 1234,
"feature": [
{
"name": "1234",
"price": {
"before": 10,
"after": 50
}
},
{
"name": "samsung",
"price": {
"before": 10,
"after": 20
}
},
{
"name": "apple",
"price": {
"before": 10,
"after": 0
}
},
{
"name": "lenovo",
"price": {
"before": 0,
"after": 30
}
}
]
}
]
};
3.) Please try to get the desired output from input yourself as this will help you learn a lot of things in between, as suggested by some please use map, filter, forEach for your requirement.
Hope this helps. Thanks!
You could take a nested approach for grouping.
var data = { before: { device: [{ id: "1234", price: "10", features: [{ name: "samsung", price: "10" }, { name: "Apple", price: "20" }] }, { id: "2154", price: "20", features: [{ name: "samsung", price: "30" }, { name: "Moto", price: "40" }] }] }, after: { device: [{ id: "1234", price: "50", features: [{ name: "samsung", price: "20" }, { name: "Lenovo", price: "30" }] }, { id: "2158", price: "40", features: [{ name: "samsung", price: "30" }] }] } },
cols = Object.fromEntries(Object.keys(data).map(k => [k, 0])),
result = Object.values(Object.entries(data).reduce((r, [col, { device }]) => {
device.forEach(({ id, price, features }) => {
r[id] = r[id] || [{ id, ...cols }];
r[id][0][col] = price;
features.forEach(({ name, price }) => {
let temp = r[id].find(q => q.name === name);
if (!temp) r[id].push(temp = { name, ...cols });
temp[col] = price;
});
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use lodash library for grouping
https://lodash.com/docs/3.10.1#groupBy
Comparing 2 objects, and output equivalent values
var has = {"before":[{
name: 'Nokia',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "24 hours battery backup",
}
}],
"after":[{
name: 'Samsung',
os: 'Andriod',
features: {
camera: "200 MPixel Camera",
battery: "30 hours battery backup",
}
}]
};
function compare(Pro1, Pro2) {
var Val1 = Object.values(Pro1);
var Val2 = Object.values(Pro2);
var equivalent = [];
var keys = Object.keys(Pro1);
keys.forEach(k => {
if (Pro1.hasOwnProperty(k) && Pro2.hasOwnProperty(k)) {
if (typeof Pro1[k] === 'object') {
let recursiveResult = compare(Pro1[k], Pro2[k]);
equivalent.push(...recursiveResult);
} else if (Pro1[k] === Pro2[k]) {
equivalent.push(Pro1[k]);
}
}
});
return equivalent;
}
let equiv = compare(has["before"], has["after"]);
console.log(equiv);
I want to create a new array based on an original array but with merged data.
Every name key need to have merged date+time (format: YYYY-MM-DD HH:MM) with merged scores. All unique datetimes need to be available as key for each name.
ARRAY ORIGINAL:
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
ARRAY THAT I WANT:
{
[A]: {
"2017-05-16 00:00": 1,
"2017-05-16 00:01": 2
},
[B]: {
"2017-05-16 00:00": 0,
"2017-05-16 00:01": 1
}
}
I hope you guys can help me out. I can't even think of an efficiƫnt way to do this, unfortunately. I tried to solve this issue with 5 foreach statements with no luck :(
You could use two arrays for names and times as closure and generate for all names and times a property with zero value.
var data = { data: [{ name: "A", history: [{ created: "2017-05-16 00:00:00", score: "1" }, { created: "2017-05-16 00:01:10", score: "1" }, { created: "2017-05-16 00:01:30", score: "1" }] }, { name: "B", history: [{ created: "2017-05-16 00:01:00", score: "1" }] }] },
result = data.data.reduce(function (names, times) {
return function (r, a) {
if (!r[a.name]) {
r[a.name] = {};
times.forEach(function (time) {
r[a.name][time] = 0;
});
names.push(a.name);
}
a.history.forEach(function (o) {
var time = o.created.slice(0, 16);
if (times.indexOf(time) === -1) {
names.forEach(function (name) {
r[name][time] = 0;
});
times.push(time);
}
r[a.name][time] += +o.score;
});
return r;
};
}([], []), {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You have to create an object not an array, As arrays cannot have a key-value pair in javascript. There is no associative array concept in javascript. You have to use objects in javascript for that.
Here is how you can do what you are trying to achieve using objects.
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}]
};
var result ={};
value.data.forEach(function(v){
var score = {};
for(var i=0;i<v.history.length;i++){
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);
Now you can access data as result.A or result[A] and result.B or result[B]
SNIPPET
value = {
"data": [{
"name": "A",
"history": [{
"created": "2017-05-16 00:00:00",
"score": "1"
},
{
"created": "2017-05-16 00:01:10",
"score": "1"
},
{
"created": "2017-05-16 00:01:30",
"score": "1"
}
]
},
{
"name": "B",
"history": [{
"created": "2017-05-16 00:01:00",
"score": "1"
}]
}
]
};
var result = {};
value.data.forEach(function(v) {
var score = {};
for (var i = 0; i < v.history.length; i++) {
score[v.history[i].created] = v.history[i].score;
}
result[v.name] = score;
});
console.log(result);