Reputation: 43
I was wondering how can I do something similar to compare between plan prices or between characteristics of something but maintaining the length of items of the value with most checks described, example:
- | Regulartz | Regulartz
King | King | King
Individual | Individual | Individual
Normal | Normal | Normal
Queen | - | -
- | - | Cal King
I wanna do this comparison table, and If I do not have any value, put an "X" on it.
My arrays are silimar to this:
arr1 = [
0: {name: "King"}
1: {name: "Individual"}
2: {name: "Normal"}
3: {name: "Queen"}
]
arr2 = [
0: {name: "Regulartz"}
1: {name: "King"}
2: {name: "Individual"}
3: {name: "Normal"}
4: {name: "Cal King"}
]
...etc
I did something like
const sizeLength = sizes.map((size, idx) => (
size.name.includes(sizes[idx].name)
))
But I don't have the comparison between one array with other wish contains a length > than the other.
Is any 'lodash' utility for this?
Thanks for your help!
Upvotes: 2
Views: 113
Reputation: 35222
You need to
td
for each planYour initial data looks something similar to this. Just creating an array of objects so that more plans can be added.
const plans = [
{
planName: 'plan A',
features: [
{ name: 'Regulartz' },
{ name: 'King' },
{ name: 'Individual' },
{ name: 'Normal' },
{ name: 'Cal King' }
]
},
{
planName: 'plan B',
features: [
{ name: 'King' },
{ name: 'Individual' },
{ name: 'Normal' },
{ name: 'Queen' }
]
}
]
In render
method, you could use array methods like some
to check each plan and its nested features. But, it becomes very expensive operation because you'd have to do it for every td
cell. So, you could create an object lookup which has each plan
as key and the each feature as that plan's nested key. Also, create a unique Set
of all the features in all plans.
const mapper = { },
allFeaturesSet = new Set();
for (const { planName, features } of plans) {
mapper[planName] = {};
for (const { name } of features) {
mapper[planName][name] = true;
allFeaturesSet.add(name)
}
}
const allFeatures = Array.from(allFeaturesSet) // convert set to array
If you have a relational database, you could get this type of data from the server itself. You could do a join between the features and the plans table to get each plan and it's feature mapping. But, since you have arrays, you'd have to loop and create a mapper.
You could also get the unique plans in a separate call like this:
const allFeatures = Array.from(
new Set(plans.flatMap(a => a.features.map(a => a.name)))
);
In render, loop through the plans and create headers for each plan. Loop through each feature and create a row. Inside tr
. loop through the plan and check if the mapper object has an entry for the current plan and feature and conditionally display the data
<table>
<thead>
<tr>
{plans.map(a => <th>{a.planName}</th>)}
</tr>
</thead>
{allFeatures.map(f => (
<tr>
{plans.map(a => <td>{mapper[a.planName][f] ? f : '--'}</td>)}
</tr>
))}
</table>
Here's a stackblitz demo
Snippet:
function App() {
const plans = [
{
planName: 'planA',
features: [
{ name: 'Regulartz' },
{ name: 'King' },
{ name: 'Individual' },
{ name: 'Normal' },
{ name: 'Cal King' }
]
},
{
planName: 'planB',
features: [
{ name: 'King' },
{ name: 'Individual' },
{ name: 'Normal' },
{ name: 'Queen' }
]
}
];
const allFeatures = Array.from(
new Set(plans.flatMap(a => a.features.map(a => a.name)))
);
const mapper = {};
for (const { planName, features } of plans) {
mapper[planName] = {};
for (const { name } of features)
mapper[planName][name] = true;
}
return (
<table>
<thead>
<tr>
{plans.map(a =>
<th>{a.planName}</th>
)}
</tr>
</thead>
{allFeatures.map(f => (
<tr>
{plans.map(a => (
<td>{mapper[a.planName][f] ? f : '--'}</td>
))}
</tr>
))}
</table>
);
}
ReactDOM.render(
<App />,
document.getElementById("react")
);
table {
border-collapse: collapse;
}
th, tr, td {
border: 1px solid black;
padding: 5px
}
<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="react"></div>
Upvotes: 2
Reputation: 538
You'll have to iterate the longest array and for each element in there check each of the shorter arrays if the value exists, if it does- you're good to go, if not- add an x to it. So something similar to:
arrPremium.forEach((el, idx) => { // assuming this array holds the complete list
if(!arrMedium.some(e => e.name == el.name)) arrMedium.splice(idx, 0, {name: "x"})
});// assuming arrMedium is the shorter array;
A better way still will be to create a new array and push the value (either name or x) to it, instead of modifying the original array, so:
let newArr = [];
arrPremium.forEach((el, idx) => {
let newEl = arrMedium.some(e => e.name == el.name) ? {name: el.name} : {name: "x"};
newArr.push(newEl);
});
Upvotes: 2