I have an array stating salary of different sectors. I need to calculate and then create a table based on this . I'm really confused how to do it . Here is an example data
const data=[
['Euro','Tech'],
['USD','Tech'],
['GBX', 'Health'],
['Euro', 'Real Estate'],
['GBX', 'Real Estate'].
]
Now I have to display the sector ,salary & total in the Table like this below:
Sector
Euro
GBX
USD
Total
Tech
1
0
1
2
Health
0
1
0
1
Real Estate
1
1
0
2
Total
2
2
1
5
Could you help me with this. I'm using React table to display the data.
Here the idea is to create a two dimensional array filled with zeros, then work through each item in the data array and increment the correct value in the two diminsional array based on a lookup using a map of sector names to indexes and a map of currency names to indexes.
Hopefully it helps, though I feel like there's probably a better way to do it.
const data = [
['Euro','Tech'],
['USD','Tech'],
['GBX', 'Health'],
['Euro', 'Real Estate'],
['GBX', 'Real Estate'],
['GBX', 'Health'],
];
const array_unique = (arr) => Array.from(new Set(arr));
const sectors = array_unique( data.map(([_, sector]) => sector) );
const currencies = array_unique( data.map(([currency]) => currency) ).sort();
const sector_map = Object.fromEntries(
sectors.map((sector, index) => [sector, index])
);
const currency_map = Object.fromEntries(
currencies.map((currency, index) => [currency, index])
);
// zero fill 2 dimensional array
const values_matrix = sectors.map( () => currencies.map(() => 0) );
// increment values in the 2 dimensional array for each item in the data array
// getting the row index and column index from the sector_map and currency_map
for(const [currency, sector] of data) {
values_matrix[ sector_map[sector] ][ currency_map[currency] ]++;
}
// create rows for a table
const rows = [['Sector', ...currencies]];
for(const [index, sector] of sectors.entries()) {
rows.push([sector, ...values_matrix[index]]);
}
console.log(rows.map((row) => row.join(',')));
try this code to format data array
const data = [
['Euro', 'Tech'],
['USD', 'Tech'],
['GBX', 'Health'],
['Euro', 'Real Estate'],
['GBX', 'Real Estate'],
];
let res = {};
let currencies = [];
data.map((item) => {
const [val, key] = item;
res[key] ? res[key].push(val) : (res[key] = [val]);
if (!currencies.includes(val)) currencies.push(val);
});
const rows = Object.keys(res); //Tech, Health, Real Estate
const table = new Array(rows.length);
let index = 0;
for (let row = 0; row < currencies.length; row++) {
key = rows[row];
const values = Object.values(res[key]);
table[index] = { title: key, values: new Array(currencies.length) };
for (let i = 0; i < currencies.length; i++) {
const element = currencies[i];
if (values.includes(element)) {
table[index].values[i] = { title: element, value: 1 };
} else {
table[index].values[i] = { title: element, value: 0 };
}
}
index++;
}
console.log(JSON.stringify(table, null, 2));
result will be like this
[
{
"title": "Tech",
"values": [
{
"title": "Euro",
"value": 1
},
{
"title": "USD",
"value": 1
},
{
"title": "GBX",
"value": 0
}
]
},
{
"title": "Health",
"values": [
{
"title": "Euro",
"value": 0
},
{
"title": "USD",
"value": 0
},
{
"title": "GBX",
"value": 1
}
]
},
{
"title": "Real Estate",
"values": [
{
"title": "Euro",
"value": 1
},
{
"title": "USD",
"value": 0
},
{
"title": "GBX",
"value": 1
}
]
}
]
Related
I'm working on school-app. person enter students marks from frontend and I've to store it in my backend. I know my data-structure is quite bad. but this is only way I can comfortly use and fit it in my front end application/website.
codeSandbox link
Full Code:
//This data is already set need to push information in this array.
let student = [{
"detail": {
"name": "Mark",
"surname":"widen"
},
}];
//formatting the query in json.
const keys = Object.keys(query)[0].split(",")
const values = Object.values(query)[0].split(",")
const newObj = {}
for (let i = 0; i < keys.length; i++) {
newObj[keys[i]] = values[i]
}
// I've to push it along with "academic-year". so,
for (let a = 0; a < newObj.length; a++) {
const year = a + "st-Year"
console.log(year) // Expected Output: 1st-Year and 2nd-Year
}
// How to run this both for-loop synchronously way ?? AND
//pushing with "ObtainedMarks" and "year" (Error over here)
student.push({
ObtainedMarks: {
year : [
{ physics: newObj }
],
year : [
{ physics: newObj }
]
}
})
console.log(student) //Here's I want expected Output
Expected Output:
let student = [{
"detail": {
"name": "Mark",
"surname":"widen"
},
ObtainedMarks: {
"1st-Year": [
{ physics: { "marks": "500" } } //Physics subject is default.
],
"2nd-Year": [
{ physics: { "mark": "200" } } //Physics subject is default.
]
}
}];
I want to push returned data in student array. with 1st-Year
and 2nd-Year's for-loop.
You can do the conversion in your for-loop
let student = [{
"detail": {
"name": "Mark",
"surname": "widen"
},
}];
let query = {
"marks,mark": "500,200"
}
const keys = Object.keys(query)[0].split(",");
const values = Object.values(query)[0].split(",");
const marks = {}
for (let i = 0; i < keys.length; i++) {
marks[i === 0 ? `${i+1}st-year` : `${i+1}nd-year`] = [{
physics: {
[keys[i]]: values[i]
}
}];
}
student.push({
obtainedMarks: marks
});
console.log(student);
Alternative way: map through the keys and create an object from entries after manipulating the data.
let student = [{
"detail": {
"name": "Mark",
"surname": "widen"
},
}];
let query = {
"marks,mark": "500,200"
}
const keys = Object.keys(query)[0].split(",");
const values = Object.values(query)[0].split(",");
const marks = Object.fromEntries(keys.map((k, i) => {
return [
i === 0 ? `${i+1}st-year`: `${i+1}nd-year`,
[{ physics: { [k]: values[i] }}]
];
}));
student.push({
obtainedMarks: marks
});
console.log(student);
I am trying to categorise the objects by comparing two objects say data and categories
const data = {
"1a": {
"name": "1a",
"count": 154
},
"1b": {
"name": "1b",
"count": 765
},
"1c": {
"name": "1c",
"count": 7877
},
"777": {
"name": "777",
"count": 456
}
};
const categories = {
"A_category":["A","1a", "2a"],
"B_category":["1b", "2b"],
"C_category":["1c", "2c"],
"D_category":["1d", "2d"]
};
I want to group the data based on the category object, when there is no match the group should be others and the resultant data should be like
const resultData = [
{ group: 'Others', name: '777', count: 456 },
{ group: 'A_category', name: '1a', count: 154 },
{ group: 'B_category', name: '1b', count: 765 },
{ group: 'C_category', name: '1c', count: 7877 }
]
I used the function but not able to achieve the result
const resultData = [];
function restructure(data, categories) {
Object.keys(data).map(
dataKey => {
for (let [key, value] of Object.entries(categories)) {
value.includes(dataKey) ? resultData.push({"group": key,...data[dataKey]}) : resultData.push({"group": "Others",...data[dataKey]}) ;
break;
}
}
)
}
restructure(data,categories);
You can try this as well. Iterate over your data entries and find whether the key exists in any of the categories object data and push it into the array with found category as group or push it with Others as group as shown in the below code
const data = {
"1a": {
"name": "1a",
"count": 154
},
"1b": {
"name": "1b",
"count": 765
},
"1c": {
"name": "1c",
"count": 7877
},
"777": {
"name": "777",
"count": 456
}
};
const categories = {
"A_category": ["A", "1a", "2a"],
"B_category": ["1b", "2b"],
"C_category": ["1c", "2c"],
"D_category": ["1d", "2d"]
};
const resultData = [];
Object.entries(data).map(([key, val])=>{
let group = Object.keys(categories).find(category=>categories[category].includes(key)) || 'Others'
resultData.push({
group,
...val
})
})
console.log(resultData)
Instead of for loop you need to use filter as let category = Object.entries(categories).filter(([key, value]) => value.includes(dataKey));.
If category.length > 0 then category is available else use Others.
Try it below.
const data = {
"1a": {
"name": "1a",
"count": 154
},
"1b": {
"name": "1b",
"count": 765
},
"1c": {
"name": "1c",
"count": 7877
},
"777": {
"name": "777",
"count": 456
}
};
const categories = {
"A_category": ["A", "1a", "2a"],
"B_category": ["1b", "2b"],
"C_category": ["1c", "2c"],
"D_category": ["1d", "2d"]
};
const resultData = [];
function restructure(data, categories) {
Object.keys(data).map(
dataKey => {
let category = Object.entries(categories)
.filter(([key, value]) => value.includes(dataKey));
resultData.push({
"group": category.length > 0 ? category[0][0] : "Others",
...data[dataKey]
});
})
}
restructure(data, categories);
console.log(resultData);
That's because you're breaking out of the loop regardless of whether you found the category or not. Your for loop will only execute once then breaks immediately. If the first category object matches, it is used, if not "Others" is assigned and the loop exits without checking the rest of the categories. Only break out of the loop if the lookup is successful:
for (let [key, value] of Object.entries(categories)) {
if(value.includes(dataKey)) { // if this is the category
resultData.push({ "group": key, ...data[dataKey] }); // use it ...
return; // ... and break the loop and the current iteration of forEach. The current object is handled
}
}
resultData.push({ "group": "Others", ...data[dataKey] }); // if the return statement above is never reached, that means the category was not found, assign "Others"
BTW, you can use other array methods to shorten things out like so:
function restructure(data, categories) {
return Object.keys(data).map(key => ({
"group": Object.keys(categories).find(cat => categories[cat].includes(key)) || "Others",
...data[key]
}));
}
Then use like so:
const resultData = restructure(data, categories);
My method uses find to try to find a category key that contains the name of the object, if find fails, it returns null at which point, the || "Others" part is evaluated and "Others" will be used as the group name (Does JavaScript have "Short-circuit" evaluation?).
Demo:
const data = {"777":{"name":"777","count":456},"1a":{"name":"1a","count":154},"1b":{"name":"1b","count":765},"1c":{"name":"1c","count":7877}};
const categories = {"A_category":["A","1a","2a"],"B_category":["1b","2b"],"C_category":["1c","2c"],"D_category":["1d","2d"]};
function restructure(data, categories) {
return Object.keys(data).map(key => ({
"group": Object.keys(categories).find(cat => categories[cat].includes(key)) || "Others",
...data[key]
}));
}
const resultData = restructure(data, categories);
console.log(resultData);
In JavaScript I have 2 object arrays that have the same objects but are in a different order. I'm trying to figure out how to sort one array based on the order of the other. There is a unique field they both share (sortField below) I'm just failing on figuring out how to sort with it. Here's an example of my arrays:
sorter array:
[
{
"displayName": "Party",
"sortField": "com.uniqueXbd",
"elementId": "PtyListPanel"
}, {
"displayName": "Group",
"sortField": "com.uniqueARd",
"elementId": "GrpListPaneARd"
}, {
"displayName": "Leader",
"sortField": "com.uniqueEcF",
"elementId": "LeaderListPaneEcF"
}
]
needsSorted array:
[
{
"displayName": "Group",
"sortField": "com.uniqueARd",
"elementId": "GrpListPaneARd"
}, {
"displayName": "Leader",
"sortField": "com.uniqueEcF",
"elementId": "LeaderListPanel"
}, {
"displayName": "Party",
"sortField": "com.uniqueXbd",
"elementId": "PtyListPaneEcF"
}
]
I'm guessing it's going to look something like this?
needsSorted.sort((a, b) => {
if(sorter.sortField...){
return 1
})
Thanks
const output = [];
sortedArray.forEach( sortedItem => {
const matchingItem = unsortedArray.find( unsortedItem => unsortedItem.sortField === sortedItem.sortField );
if(matchingItem){
output.push(matchingItem);
}
});
Since you know the second array is the order you want the items from the first array to be in, you should loop through it. Then find the matching item from the first list, and push it into your output in that order.
You can make a sorting lookup that maps the sort key to the index in the original array. Then in your sort, you can look it up for both objects in the comparison.
This replaces the repeated need to lookup the index in the original array for each comparison with a constant time object lookup so it should be more performant for larger arrays at the expense of the space for the lookup object.
let sortObj = [{"displayName": "Party","sortField": "com.uniqueXbd","elementId": "PtyListPanel"}, {"displayName": "Group","sortField": "com.uniqueARd","elementId": "GrpListPaneARd"}, {"displayName": "Leader","sortField": "com.uniqueEcF","elementId": "LeaderListPaneEcF"}]
let needsSorted = [{"displayName": "Group","sortField": "com.uniqueARd","elementId": "GrpListPaneARd"}, {"displayName": "Leader","sortField": "com.uniqueEcF","elementId": "LeaderListPanel"}, {"displayName": "Party","sortField": "com.uniqueXbd","elementId": "PtyListPaneEcF"}]
let sortLookup = sortObj.reduce((obj, item, idx) => {
obj[item.sortField] = idx
return obj
}, {})
needsSorted.sort((a,b) => sortLookup[a.sortField] - sortLookup[b.sortField])
console.log(needsSorted)
var obj = [
{
"one": 1,
"two": 9
}, {
"one": 3,
"two": 5
}, {
"one": 1,
"two": 2
}
];
var obj = [
{
"one": 1,
"two": 2,
}, {
"one": 1,
"two": 9
}, {
"one": 3,
"two": 5
}
];
obj.sort(function(a, b) {
return a["one"] - b["one"] || a["two"] - b["two"];
});
const sortedIndexes = sorter.map(i => i.sortField);
needsSorted.sort((a, b) => {
const aIndex = sortedIndexes.findIndex((i) => i === a.sortField);
const bIndex = sortedIndexes.findIndex((i) => i === b.sortField);
return aIndex - bIndex;
})
Given that you just want to compare the two arrays and make sure they are still the same, I would go about it differently:
const first = sorted.sort((a, b) => a.localCompare(b))
const second = needsSorting.sort((a, b) => a.localCompare(b))
if (JSON.stringify(first) != JSON.stringify(second)) {
console.log("the array was modified!");
}
const sortOrder = sorted.map(item => item.sortField);
needsSorted.sort((a, b) => {
return sortOrder.indexOf(a.sortField) > sortOrder.indexOf(b.sortField) ? 1 : -1;
});
const fields = sorted.map(x => x.sortField);
const value = x => fields.indexOf(x.sortField);
needSorted.sort((a, b) => value(a) - value(b));
console.log(needSorted);
const sorted = [
{
displayName: "Party",
sortField: "com.uniqueXbd",
elementId: "PtyListPanel"
},
{
displayName: "Group",
sortField: "com.uniqueARd",
elementId: "GrpListPaneARd"
},
{
displayName: "Leader",
sortField: "com.uniqueEcF",
elementId: "LeaderListPaneEcF"
}
];
const needSorted = [
{
displayName: "Group",
sortField: "com.uniqueARd",
elementId: "GrpListPaneARd"
},
{
displayName: "Leader",
sortField: "com.uniqueEcF",
elementId: "LeaderListPanel"
},
{
displayName: "Party",
sortField: "com.uniqueXbd",
elementId: "PtyListPaneEcF"
}
];
const fields = sorted.map(x => x.sortField);
const value = x => fields.indexOf(x.sortField);
needSorted.sort((a, b) => value(a) - value(b));
console.log(needSorted);
I have an array that looks like this:
var array = [[
{ "loc": {} },
{ "distance": 6.4 },
{ "zip1": "06120" },
{ "zip2": "06095" },
{ "group": 1 },
{ "weight": 1119 }
], [
{ "loc": {} },
{ "distance": 6.41 },
{ "zip1": "06095" },
{ "zip2": "06120" },
{ "group": 2 },
{ "weight": 41976 }
], [
{ "loc": {} },
{ "distance": 6.41 },
{ "zip1": "06095" },
{ "zip2": "06120" },
{ "group": 1 },
{ "weight": 41976 }
]];
Now I want to take the array values based on the property values for show in HTML.
Expected output is split into array with "group" property. I also need to store in HTML with based on group, as shown in the example below:
group 1:
all zip1's under group 1
group 2:
all zip1's under group 2
I tried using a loop but I didn't manage to get the right answer:
for (var k = 0; k < array.length; k++) {
var array1 = array[k];
if (flag[array1[2]["zip1"]]) continue;
flag[array1[2]["zip1"]] = true;
output2.push(array1);
}
So help me to find split the array show in HTML with group wise
Using reduce, you can create an object with each group value as key and an array of zip1 as values like this:
Then loop through the Object.entries, to create the HTML:
const array = [[{"loc":{}},{"distance":6.4},{"zip1":"06120"},{"zip2":"06095"},{"group":1},{"weight":1119}],[{"loc":{}},{"distance":6.41},{"zip1":"06095"},{"zip2":"06120"},{"group":2},{"weight":41976}],[{"loc":{}},{"distance":6.41},{"zip1":"06095"},{"zip2":"06120"},{"group":1},{"weight":41976}]];
const merged = array.reduce((r, a) =>{
const { group } = a.find(n => n.group)
const { zip1 } = a.find(n => n.zip1)
r[group] = r[group] || []
r[group].push(zip1)
return r;
},{})
const output = document.getElementById('output');
Object.entries(merged).forEach(([group, zips]) => {
const h1 = document.createElement('h1');
h1.innerHTML = "group " + group
const span = document.createElement('span');
span.innerHTML = `Zip1 - ${zips} (in group - ${group})`;
output.appendChild(h1)
output.appendChild(span)
})
<div id="output"></div>
I have a JSON array of products with nested array of stores that supply them:
let arrayOfProducts =
[
{
"title": "ProductA",
"stores": [
{
"name": "Store1",
"price": 15.09
},
{
"name": "Store2",
"price": 16.30,
},
{
"name": "Store4",
"price": 16.55,
},
.
.
.
"title": "ProductB",
"stores": [
{
"name": "Store1",
"price": 8.06
},
{
"name": "Store3",
"price": 9.25,
},
{
"name": "Store4",
"price": 9.27,
},
.
.
.
]
I need to find the combination of the minimum number of store(s)(due to extra shipping constraint) that provide all of the products at the lowest TOTAL price.
e.g. lets say the array has five products ProductA-ProductE.There is no single store in their respective arrays that can supply all of them. Store2 supplies a subset of the products and so does any other store.
The output should be like that:
[
{
"name": "store1",
"price": total_price_for_this_store,
"products": [ "ProductC"]
},
{
"name": "store2",
"price": total_price_for_this_store,
"products": [ "ProductA", "ProductB", "ProductD"]
},
{
"name": "store3",
"price": total_price_for_this_store,
"products": [ "ProductE"]
}
]
I have managed to create the expected output using javascipt's forEach and filter functions, but only to find the solution if one or more stores have ALL the products and not a subset of them.
let results = []
arrayOfProducts.forEach((product) => {
product.stores.forEach(store => {
let storeIndex = results.findIndex(el => { return el.name === store.name })
if (storeIndex === -1) { // first occurence of the shop in the array of results
results.push({
name: store.name,
price: store.price,
products : [product.title]
})
} else {
results[storeIndex].price += store.price
results[storeIndex].products.push(product.title)
}
})
})
let allProducts = results.filter((store) => {
return store.products.length === arrayOfProducts.length
})
allProducts.sort(function (a, b) {
return parseFloat(a.price) - parseFloat(b.price)
})
How can i approach this problem?I dont know how to start.
Does it belong to the LP category of algorithms?
I've managed to come up with a solution:
const fs = require('fs')
const _ = require('lodash')
// loading the product JSON file
let product = JSON.parse(fs.readFileSync('product.json', 'utf8'))
// create a sorted array of the title products
let productTitles = product.map(el => {
return el.title
}).sort(sortAlphabetically)
let numberOfProducts = productTitles.length
let storeCombinations = []
let stores = []
// create the array of stores
product.forEach((product) => {
product.stores.forEach(store => {
let price = store.price
let productUrl = store.productUrl
let storeIndex = stores.findIndex(el => { return el.name === store.name })
if (storeIndex === -1) { // first occurence of the shop in the array of results
stores.push({
name: store.name,
products: [{
title: product.title,
price: (parseFloat(price) * product.quantity).toFixed(2)
}]
})
} else {
stores[storeIndex].products.push({
title: product.title,
price: (parseFloat(price) * product.quantity).toFixed(2),
})
}
})
})
let comboCnter = 0
// for each of the stores see if the missing product(s) can be complemented
// with any of the following stores.
// If true then merge the two store products
stores.forEach((el, index) => {
for (let i = index + 1; i < stores.length; i++) {
let currentStoreProducts = el.products.map(product => product.title).sort(sortAlphabetically)
let nextStoreProducts = stores[i].products.map(product => product.title).sort(sortAlphabetically)
let mergedArrays = _.uniq(currentStoreProducts.concat(nextStoreProducts))
if (mergedArrays.length === numberOfProducts) {
let products1 = []
let products2 = []
let store1Price = 0
let store2Price = 0
productTitles.forEach(title => {
let index1 = el.products.findIndex(x => x.title === title)
let index2 = stores[i].products.findIndex(x => x.title === title)
if (index1 !== -1 && index2 !== -1) {
if (parseFloat(el.products[index1].price) < parseFloat(stores[i].products[index2].price)) {
store1Wins()
} else {
store2Wins()
}
}
if (index2 === -1) {
store1Wins()
}
if (index1 === -1) {
store2Wins()
}
function store1Wins() {
store1Price = (parseFloat(el.products[index1].price) + parseFloat(store1Price)).toFixed(2)
products1.push({
title: el.products[index1].title,
productUrl: el.products[index1].productUrl
})
}
function store2Wins() {
store2Price = (parseFloat(stores[i].products[index2].price) + parseFloat(store2Price)).toFixed(2)
products2.push({
title: stores[i].products[index2].title,
productUrl: stores[i].products[index2].productUrl
})
}
})
storeCombinations.push({
totalPrice: (parseFloat(store1Price) + parseFloat(store2Price)).toFixed(2),
store1: {
name: el.name,
price: store1Price,
products: products1
},
store2: {
name: stores[i].name,
price: store2Price,
products: products2
}
})
comboCnter++
}
}
})
// sort the final result ascending prices
storeCombinations.sort((a, b) => {
return parseFloat(a.totalPrice) - parseFloat(b.totalPrice)
})
fs.writeFileSync('storeCombinations.json', JSON.stringify(storeCombinations))
console.log('comboCnter: ' + comboCnter)
function sortAlphabetically(a, b) {
let nameA = a.toLowerCase()
let nameB = b.toLowerCase()
if (nameA < nameB) { return -1 }// sort string ascending
if (nameA > nameB) { return 1 }
return 0 // default return value (no sorting)
}
This code finds the cheapest combination of two stores.