I have this payload which I'm trying to execute some functions on in JavaScript:
{
"markets": [
{
"mtId": 27,
"id": 1,
"cId": "27-1",
"mt": "OVER_UNDER",
"selections": [
{
"id": 1,
"price": 1.0896773820446435,
"selectionStatus": 1,
"name": "Over 0.5"
},
{
"id": 2,
"price": 12.159031085167172,
"selectionStatus": 1,
"name": "Under 0.5"
}
],
"marketName": "Over Under 0.5"
},
{
"mtId": 27,
"id": 2,
"cId": "27-2",
"mt": "OVER_UNDER",
"selections": [
{
"id": 1,
"price": 1.4531444546407393,
"selectionStatus": 1,
"name": "Over 1.5"
},
{
"id": 2,
"price": 3.207355058969988,
"selectionStatus": 1,
"name": "Under 1.5"
}
],
"marketName": "Over Under 1.5"
},
{
"mtId": 27,
"id": 3,
"cId": "27-3",
"mt": "OVER_UNDER",
"selections": [
{
"id": 1,
"price": 2.3859593325595307,
"selectionStatus": 1,
"name": "Over 2.5"
},
{
"id": 2,
"price": 1.721681322609395,
"selectionStatus": 1,
"name": "Under 2.5"
}
],
"marketName": "Over Under 2.5"
}
]
}
Basically, I want to take the markets array, map the selections and
return the array with price differences from 0.5.
I'd then like to take that array and return the value which is closest to zero.
I can get the result from this function:
export const generateNumberClosestToZero = (markets) => {
let goal = 0;
let result = markets
.map((market) =>
market.selections.reduce(function (bookPercentage, selection) {
return 0.5 - 1 / selection.price;
}, 0)
)
.reduce(function (prev, current) {
return Math.abs(current - goal) < Math.abs(prev - goal) ? current : prev;
});
return result;
};
But what I want to do is also retrieve the index of that reduced value, so I can perform operations on that specific market (e.g. markets[1] etc. ). Is there a way to do this with my code, or a better solution than what I have so far?
You could map the index along with the value and reduce only by the value.
const
generateNumberClosestToZero = (markets) => {
let goal = 0;
return markets
.map((market, index) => [
market.selections.reduce((bookPercentage, selection) => 0.5 - 1 / selection.price, 0),
index
])
.reduce((a, b) => Math.abs(b[0] - goal) < Math.abs(a[0] - goal) ? b : a);
},
data = { markets: [{ mtId: 27, id: 1, cId: "27-1", mt: "OVER_UNDER", selections: [{ id: 1, price: 1.0896773820446435, selectionStatus: 1, name: "Over 0.5" }, { id: 2, price: 12.159031085167172, selectionStatus: 1, name: "Under 0.5" }], marketName: "Over Under 0.5" }, { mtId: 27, id: 2, cId: "27-2", mt: "OVER_UNDER", selections: [{ id: 1, price: 1.4531444546407393, selectionStatus: 1, name: "Over 1.5" }, { id: 2, price: 3.207355058969988, selectionStatus: 1, name: "Under 1.5" }], marketName: "Over Under 1.5" }, { mtId: 27, id: 3, cId: "27-3", mt: "OVER_UNDER", selections: [{ id: 1, price: 2.3859593325595307, selectionStatus: 1, name: "Over 2.5" }, { id: 2, price: 1.721681322609395, selectionStatus: 1, name: "Under 2.5" }], marketName: "Over Under 2.5" }] };
console.log(generateNumberClosestToZero(data.markets));
I think this is what you're looking for.
const markets = [{"mtId": 27,"id": 1,"cId": "27-1","mt": "OVER_UNDER","selections": [{"id": 1,"price": 1.0896773820446435,"selectionStatus": 1,"name": "Over 0.5"},{"id": 2,"price": 12.159031085167172,"selectionStatus": 1,"name": "Under 0.5"}],"marketName": "Over Under 0.5"},{"mtId": 27,"id": 2,"cId": "27-2","mt": "OVER_UNDER","selections": [{"id": 1,"price": 1.4531444546407393,"selectionStatus": 1,"name": "Over 1.5"},{"id": 2,"price": 3.207355058969988,"selectionStatus": 1,"name": "Under 1.5"}],"marketName": "Over Under 1.5"},{"mtId": 27,"id": 3,"cId": "27-3","mt": "OVER_UNDER","selections": [{"id": 1,"price": 2.3859593325595307,"selectionStatus": 1,"name": "Over 2.5"},{"id": 2,"price": 1.721681322609395,"selectionStatus": 1,"name": "Under 2.5"}],"marketName": "Over Under 2.5"}];
const generateNumberClosestToZero = (markets) => {
let closest = 9999; // closest value found so far
let index = []; // output
markets.forEach((m, n) => {
m.selections.forEach((s, t) => {
if (s.price < closest) { // if closer value found
closest = s.price; // set closest value to new value
index[0] = n; // store market index
index[1] = t; // store selections index
}
})
});
return index;
};
const closest = generateNumberClosestToZero(markets);
console.log(closest); // get indexes
console.log(markets[closest[0]].selections[closest[1]]); // access results from market
Output:
[
0,
0
]
{
"id": 1,
"price": 1.0896773820446435,
"selectionStatus": 1,
"name": "Over 0.5"
}
Related
I want to simplify and get last part missing.
So, I have an array of objects like:
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
I need to add the percentage based on qty and overall create a new object with detail of only companies with percentage greater than "X" (let's say 10) and others merged in a "other companies", like a similar
{
"idCompany": 2,
"name": "bbb",
"percentage": 18.181818181818183,
"qty": 14
},{
"idCompany": 5,
"name": "eee",
"percentage": 71.42857142857143,
"qty": 55
},{
"idCompany": null,
"name": "others",
"percentage": 10.391 // 100 - 71.42xxx - 18.18
"qty": 8 // 1 + 2 + 5
},
So, my steps:
Get the total:
const total = data.reduce((i, el) => i+el.qty, 0);
Add the percentage to start object:
let rawData = data.map(el => {
return {
name: el.company,
qty: el.qty,
idCompany: el.id,
percentage: (el.qty/total)*100,
}
})
Get only companies with percentage greater than X (e.g. 10)
let consolidateCompanies = rawData.filter(el => el.percentage > 10);
But...
Now, how can I get the OTHERS companies and add to the consolidateCompanies object? And with a more beautiful code?
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
// Get the total
const total = data.reduce((i, el) => i+el.qty, 0);
// Add percentage to the objects
let rawData = data.map(el => {
return {
name: el.company,
qty: el.qty,
idCompany: el.id,
percentage: (el.qty/total)*100,
}
})
// Get only companies that have percentage greater than 10
let consolidateCompanies = rawData.filter(el => el.percentage > 10);
console.log(consolidateCompanies);
// But I'm missing 1, 3 and 4
You could do this with a couple of Array.reduce() calls.
We'd group companies either by name or 'others', adding percentage and quantity for the others.
const data = [{ "company": "aaa", "qty": 1, "id": 1 }, { "company": "bbb", "qty": 14, "id": 2 }, { "company": "ccc", "qty": 2, "id": 3 }, { "company": "ddd", "qty": 5, "id": 4 }, { "company": "eee", "qty": 55, "id": 5 } ];
const total = data.reduce((i, el) => i+el.qty, 0);
const minPercentage = 10;
const consolidateCompanies = Object.values(data.reduce((acc, el) => {
const percentage = (el.qty/total)*100;
const name = (percentage >= minPercentage) ? el.company: 'others';
const id = (percentage >= minPercentage) ? el.id: null;
acc[name] = acc[name] || { name, percentage: 0, qty: 0, id };
acc[name].percentage += percentage;
acc[name].qty += el.qty;
return acc;
}, {}))
console.log(consolidateCompanies);
.as-console-wrapper { max-height: 100% !important; }
You could seperate others and add only if necessary without grouping by usining another object.
const
data = [{ company: "aaa", qty: 1, id: 1 }, { company: "bbb", qty: 14, id: 2 }, { company: "ccc", qty: 2, id: 3 }, { company: "ddd", qty: 5, id: 4 }, { company: "eee", qty: 55, id: 5 }],
totalQty = data.reduce((t, { qty }) => t + qty, 0),
others = { idCompany: null, name: "others", percentage: 0, qty: 0 },
result = data.reduce((r, { company: name, qty, id: idCompany }) => {
const percentage = qty * 100 / totalQty;
if (percentage >= 10) {
r.push({ idCompany, name, percentage, qty });
} else {
others.qty += qty;
others.percentage = others.qty * 100 / totalQty;
}
return r;
}, []);
if (others.qty) result.push(others);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
here is the refactor of your code
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
const total = data.reduce((i, el) => i+el.qty, 0)
const startWith = [{
"idCompany": null,
"name": "others",
"percentage": 0,
"qty": 0
}]
let rawData = data.reduce((acc, value) => {
// console.log('value', value)
const withPercentage = {
name: value.company,
qty: value.qty,
idCompany: value.id,
percentage: (value.qty/total)*100,
}
if (withPercentage.percentage > 10) {
acc.push(withPercentage)
} else {
acc[0].qty += withPercentage.qty;
acc[0].percentage += withPercentage.percentage;
}
return acc;
}, startWith).filter(f => f.percentage !== 0 && f.qty !== 0);
console.log(rawData)
Use forEach instead of map and filter, and loop the Object with your required need as follows.
const minPerc =10;
const data = [{
"company": "aaa",
"qty": 1,
"id": 1
}, {
"company": "bbb",
"qty": 14,
"id": 2
}, {
"company": "ccc",
"qty": 2,
"id": 3
}, {
"company": "ddd",
"qty": 5,
"id": 4
},
{
"company": "eee",
"qty": 55,
"id": 5
}
];
// Get the total
const total = data.reduce((i, el) => i+el.qty, 0);
let consolidateCompanies = [];
let otherObj={"idCompany": null,
"name": "others",
"percentage": 0,
"qty": 0};
data.forEach(ele=>{
let perc=(ele.qty/total)*100;
if(perc>minPerc){
consolidateCompanies.push({...ele,...{percentage:perc}})
}else{
otherObj.qty +=ele.qty; otherObj.percentage+=perc
} });
consolidateCompanies.push(otherObj);
console.log(consolidateCompanies);
I use Redux to store all my products in a list. Displayed thist list looks like:
[
{
"id": 1,
"name": "BLACK TEA",
"supplieruuid": "SLIGRO",
"price": 1.10,
},
{
"id": 2,
"name": "GREEN TEA",
"supplieruuid": "SLIGRO",
"price": 1.10,
},
{
"id": 3,
"name": "PURPLE TEA",
"supplieruuid": "BUNZL",
"price": 1.10,
},
{
"id": 4,
"name": "RAINBOW TEA",
"supplieruuid": "BUNZL",
"price": 1.10,
},
]
I'm using this reduce function to group these products together by key supplieruuid.
const sortedBySupplierUUID = state.entities.cart.list.reduce(
(hash, { ["supplieruuid"]: value, ...rest }) => ({ ...hash, [value]: (hash[value] || []).concat({ ["supplieruuid"]: value, ...rest }) }),
{}
);
return Object.keys(sortedBySupplierUUID).map((key) => ({ title: key, data: sortedBySupplierUUID[key] }));
What this returns is as following:
[
{
title: "SLIGRO",
data: [
{
"id": 1,
"name": "BLACK TEA",
"price": 1.10,
},
{
"id": 2,
"name": "GREEN TEA",
"price": 1.10,
},
],
},
{
title: "BUNZL",
data: [
{
"id": 3,
"name": "PURPLE TEA",
"price": 1.10,
},
{
"id": 4,
"name": "RAINBOW TEA",
"price": 1.10,
},
],
},
]
This all works fine, except for that I a total added to the object which will count up the total price of the items in the "data" array of each object as following:
[
{
title: "SLIGRO",
total: 2.20,
data: [
{
"id": 1,
"name": "BLACK TEA",
"price": 1.10,
},
{
"id": 2,
"name": "GREEN TEA",
"price": 1.10,
},
],
},
{
title: "BUNZL",
total: 2.20,
data: [
{
"id": 3,
"name": "PURPLE TEA",
"price": 1.10,
},
{
"id": 4,
"name": "RAINBOW TEA",
"price": 1.10,
},
],
},
]
How can I achieve this by modifying the reduce function I use?
const selectSortedItems = (state) => {
const sortedBySupplierUUID = state.entities.cart.list.reduce((hash, { ["supplieruuid"]: value, ...rest }) => ({ ...hash, [value]: (hash[value] || []).concat({ ...rest }) }), {});
return Object.keys(selectSortedItems(sortedBySupplierUUID)).map(key => (
{
title: key,
total: sortedBySupplierUUID[key].reduce((acc, cur) => acc + cur.price),
data: sortedBySupplierUUID[key]
})
)};
}
More intuitive way of doing it
const selectSortedItems = (state) => {
const itemsMap = {};
state.entities.cart.list.map((item) => {
if (itemsMap[item.supplieruuid]) {
itemsMap[item.supplieruuid].total += item.price;
itemsMap[item.supplieruuid].data.push(item);
} else {
itemsMap[item.supplieruuid] = {
title: item.supplieruuid,
total: item.price,
data: [item]
}
}
});
return Object.values(itemsMap);
}
So i have this data:
let data = [
{
"purchase_id": 1,
"product": [
{
"name": "A",
"id": 1,
"transactions": [
{
"price": 5,
"qty": 2
},
{
"price": 10,
"qty": 2
}
]
},
{
"name": "B",
"id": 2,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
},
{
"purchase_id": 2,
"product": [
{
"name": "C",
"id": 3,
"transactions": [
{
"price": 5,
"qty": 2
}
]
},
{
"name": "D",
"id": 4,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
}
]
And i want to flatten array from each data.product.transactions data:
"transactions": [
{
"price",
"qty"
}
]
Expected output is:
[
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 5,
"qty": 2
},
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 10,
"qty": 2
},
{
"purchase_id": 1,
"name": "B",
"id": 2,
"price": 3,
"qty": 4
},
{
"purchase_id": 2,
"name": "C",
"id": 3,
"price": 5,
"qty": 2
},
{
"purchase_id": 2,
"name": "D",
"id": 4,
"price": 3,
"qty": 4
},
]
I have tried to use object assign, reduce but my code doesn't work. Thank you
Use nested Array.map() to create the objects, and spread into Array.concat() to flatten the sub-arrays at each level:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [].concat(...data.map(({ purchase_id, product }) =>
[].concat(...product.map(({ name, id, transactions }) =>
transactions.map((o) => ({
purchase_id,
name,
id,
...o
})
)))));
console.log(result);
If you want to avoid the temp sub-arrays, and the flattering, use nested Array.forEach() calls, and push the created objects to a predefined array:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [];
data.forEach(({ purchase_id, product }) =>
product.forEach(({ name, id, transactions }) =>
transactions.forEach((o) => result.push({
purchase_id,
name,
id,
...o
})
)));
console.log(result);
var arr = [];
data.forEach(x => {
x.product.forEach(y => {
y.transactions.forEach(z => {
z["name"] = y.name;
z["id"] = y.id;
z["purchase_id"] = x.purchase_id;
arr.push(z);
});
})
});
console.log(arr);
I want to manipulate the array with sample data.
What I'm trying to do is find the movieId in the votes data, count it, get the user's name
Data Description:
movieId: votes have multiple movieIds, but only need to import one.
movieIdLength: total number of movieId's.
name: User name with the same movieId.
For example:
var votes = [{
"id": 1,
"pollId": 1,
"movieId": 2,
"name": "James"
}, {
"id": 2,
"pollId": 1,
"movieId": 3,
"name": "Laura"
}, {
"id": 3,
"pollId": 1,
"movieId": 1,
"name": "Dan"
}, {
"id": 4,
"pollId": 1,
"movieId": 3,
"name": "Steve"
}]
what I want:
var votesResult = [{
"movieId": 2,
"movieIdLength": 1,
"name": "James"
},{
"movieId": 1,
"movieIdLength": 1,
"name": "Dan"
},{
"movieId": 3,
"movieIdLength": 2,
"name": "Laura, Steve"
}]
ES6:
const a = [{
"id": 1,
"pollId": 1,
"movieId": 2,
"name": "James"
}, {
"id": 2,
"pollId": 1,
"movieId": 3,
"name": "Laura"
}, {
"id": 3,
"pollId": 1,
"movieId": 1,
"name": "Dan"
}, {
"id": 4,
"pollId": 1,
"movieId": 3,
"name": "Steve"
}]
const r = [...new Set(a.map(x => x.movieId))]
.map(x => Object.assign({movieId: x},
{movieIdLength: a.filter(l => l.movieId === x).length},
{name: a.filter(q => q.movieId === x).map(n => n.name).join(', ')}));
console.log(JSON.stringify(r, null, 2));
Less clear but without code duplication:
const a = [{
"id": 1,
"pollId": 1,
"movieId": 2,
"name": "James"
}, {
"id": 2,
"pollId": 1,
"movieId": 3,
"name": "Laura"
}, {
"id": 3,
"pollId": 1,
"movieId": 1,
"name": "Dan"
}, {
"id": 4,
"pollId": 1,
"movieId": 3,
"name": "Steve"
}]
const r = [...new Set(a.map(x => x.movieId))]
.map(x => Object.assign({movieId: x},
((f) => Object.assign({movieIdLength: f.length, name: f.map(({name}) => name).join(', ')})
)(a.filter(({movieId}) => movieId === x))
));
console.log(JSON.stringify(r, null, 2));
You need to start with an empty list for the result array, then you loop over the data and check if the movie id is in the result list. is it is, then count movieIdCount up by 1 and append the name to the name field, otherwise add a new movie to the result array, do you want the algorithm?
I tried the following code.
var SeatWithCat = [{
"level": "Level II",
"price": 5,
"quantity": 1,
"seats": "B3"
}, {
"level": "Level II",
"price": 5,
"quantity": 1,
"seats": "B1"
}, {
"level": "Level I",
"price": 10,
"quantity": 1,
"seats": "A2"
}, {
"level": "Level III",
"price": 30,
"quantity": 1,
"seats": "C1"
}, {
"level": "Level III",
"price": 30,
"quantity": 1,
"seats": "C2"
}, {
"level": "Level V",
"price": 50,
"quantity": 1,
"seats": "E1"
}, {
"level": "Level II",
"price": 5,
"quantity": 1,
"seats": "B2"
}, {
"level": "Level VI",
"price": 2,
"quantity": 1,
"seats": "F1"
}];
var temp = [];
var jsonarr = [];
for (var i = 0; i < SeatWithCat.length; i++) {
for (var j = 1; j < SeatWithCat.length; j++) {
if (SeatWithCat[i].level === SeatWithCat[j].level) {
temp.push({
level: SeatWithCat[i].level,
quantity: SeatWithCat[i].quantity + SeatWithCat[j].quantity,
price: SeatWithCat[i].price + SeatWithCat[j].price,
seats: SeatWithCat[i].seats + "," + SeatWithCat[j].seats
});
SeatWithCat = SeatWithCat.filter(function(el) {
return el.level !== SeatWithCat[i].level;
});
jsonarr = SeatWithCat;
alert(JSON.stringify(temp));
}
}
}
var finalObj = temp.concat(jsonarr);
alert(JSON.stringify(finalObj));
Output:
[{
"level": "Level II",
"quantity": 2,
"price": 10,
"seats": "B3,B1"
}, {
"level": "Level III",
"quantity": 2,
"price": 60,
"seats": "C1,C1"
}, {
"level": "Level VI",
"quantity": 2,
"price": 4,
"seats": "F1,F1"
}, {
"level": "Level I",
"price": 10,
"quantity": 1,
"seats": "A2"
}, {
"level": "Level V",
"price": 50,
"quantity": 1,
"seats": "E1"
}]
It's Working fine for two objects having same level but if there are greater than two objects in the array with same level its not working. My requirement is to add values for any number of objects having same level.
Thanks in advance!
You can use Array.prototype.reduce() to collect unique items in an dictionary, and then transform the dictionary back to array using Array.prototype.map():
function combine(arr) {
var combined = arr.reduce(function(result, item) {
var current = result[item.level];
result[item.level] = !current ? item : {
level: item.level,
price: current.price + item.price,
quantity: current.quantity + item.quantity,
seats: current.seats + ',' + item.seats
};
return result;
}, {});
return Object.keys(combined).map(function(key) {
return combined[key];
});
}
var SeatWithCat = [{"level":"Level II","price":5,"quantity":1,"seats":"B3"},{"level":"Level II","price":5,"quantity":1,"seats":"B1"},{"level":"Level I","price":10,"quantity":1,"seats":"A2"},{"level":"Level III","price":30,"quantity":1,"seats":"C1"},{"level":"Level III","price":30,"quantity":1,"seats":"C2"},{"level":"Level V","price":50,"quantity":1,"seats":"E1"},{"level":"Level II","price":5,"quantity":1,"seats":"B2"},{"level":"Level VI","price":2,"quantity":1,"seats":"F1"}];
var result = combine(SeatWithCat);
console.log(result);
You could use a hash table as reference to the same level object in the result set.
Iterate the array and check for hash - if not set generate a new object with the actual properties. Otherwise add quantity and append seats.
This proposal uses only one loop.
var seatWithCat = [{ level: "Level II", price: 5, quantity: 1, seats: "B3" }, { level: "Level II", price: 5, quantity: 1, seats: "B1" }, { level: "Level I", price: 10, quantity: 1, seats: "A2" }, { level: "Level III", price: 30, quantity: 1, seats: "C1" }, { level: "Level III", price: 30, quantity: 1, seats: "C2" }, { level: "Level V", price: 50, quantity: 1, seats: "E1" }, { level: "Level II", price: 5, quantity: 1, seats: "B2" }, { level: "Level VI", price: 2, quantity: 1, seats: "F1" }],
result = [];
seatWithCat.forEach(function (o) {
if (!this[o.level]) {
this[o.level] = { level: o.level, price: o.price, quantity: o.quantity, seats: o.seats };
result.push(this[o.level]);
return;
}
this[o.level].quantity += o.quantity;
this[o.level].seats += ',' + o.seats;
}, Object.create(null));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }