How to most efficiently aggregate array of objects by ID? - javascript

My starting data set is an array of objects containing metrics, each containing an ID. I need to convert this data set into an array of aggregates, by ID. For example:
const startingArray = [
{ id: 1, metricA: 5, metricB: 8, metricC: 1 }
{ id: 2, metricA: 4, metricB: 0, metricC: 7 }
{ id: 1, metricA: 9, metricB: 8, metricC: 2 }
{ id: 3, metricA: 1, metricB: 8, metricC: 2 }
{ id: 3, metricA: 6, metricB: 6, metricC: 1 }
{ id: 2, metricA: 3, metricB: 1, metricC: 9 }
{ id: 1, metricA: 3, metricB: 9, metricC: 8 }
]
const aggregates = {};
startingArray.forEach((item) => {
if (!aggregates[item.id]) {
aggregates[item.id] = {
id: item.id,
metricA: item.metricA,
metricB: item.metricB,
metricC: item.metricC
}
} else {
aggregates[item.id].metricA += item.metricA,
aggregates[item.id].metricB += item.metricB,
aggregates[item.id].metricC += item.metricC
}
});
// convert to flat array using lodash toArray() method
const endingArray = toArray(aggregates);
// results:
// [
// { id: 1, metricA: 17, metricB: 25, metricC: 11 }
// { id: 2, metricA: 5, metricB: 1, metricC: 16 }
// { id: 3, metricA: 5, metricB: 8, metricC: 3 }
// ]
The arrays can be massive, what is the most efficient way of processing this data set?

You could destructure id from the object and collect the rest for getting all entries and create a new object and sum all rest properties.
const
data = [{ id: 1, metricA: 5, metricB: 8, metricC: 1 }, { id: 2, metricA: 4, metricB: 0, metricC: 7 }, { id: 1, metricA: 9, metricB: 8, metricC: 2 }, { id: 3, metricA: 1, metricB: 8, metricC: 2 }, { id: 3, metricA: 6, metricB: 6, metricC: 1 }, { id: 2, metricA: 3, metricB: 1, metricC: 9 }, { id: 1, metricA: 3, metricB: 9, metricC: 8 }],
result = Object.values(data.reduce((r, { id, ...o }) => {
Object.entries(o).forEach(([k, v]) => {
r[id] ??= { id };
r[id][k] = (r[id][k] || 0) + v;
});
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Related

How do I have a nested grouping in react js?

I Have this array:
[
{id: 6, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId:3,deductionExchangeTypeTitle: "Exchange1" ,wageTitle:"wageTitle1"}
{id: 8, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId: 3deductionExchangeTypeTitle: "Exchange1",wageTitle:"wageTitle2"}
{id: 4, deductionTypeId: 1, deductionTypeTitle:"TypeTitle2",deductionExchangeTypeId: 4,deductionExchangeTypeTitle: "Exchange2",wageTitle:"wageTitle3"}
{id: 5, deductionTypeId: 1, deductionTypeTitle:"TypeTitle2",deductionExchangeTypeId: 5, deductionExchangeTypeTitle: "Exchange3",wageTitle:"wageTitle4"}
{id: 9, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId: 3 ,deductionExchangeTypeTitle: "Exchange1",wageTitle:"wageTitle5"}
{id: 10, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId: 3,deductionExchangeTypeTitle: "Exchange1",wageTitle:"wageTitle6"}
{id: 11, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId: 3,deductionExchangeTypeTitle: "Exchange1",wageTitle:"wageTitle7"}
{id: 12, deductionTypeId: 6,deductionTypeTitle:"TypeTitle1",deductionExchangeTypeId: 3,deductionExchangeTypeTitle: "Exchange1",wageTitle:"wageTitle8"}]
And I want to grouping it in react js like this
-TypeTitle1
-Exchange1
.wageTitle1
.wageTitle2
.wageTitle6
.wageTitle7
.wageTitle8
-TypeTitle2
-Exchange2
.wageTitle3
-Exchange3
.wageTitle4
You could use Lodash to transform your data using groupBy, mapValues, and flatMap.
import _ from 'lodash';
const data = [
{
id: 6,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle1',
},
{
id: 8,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle2',
},
{
id: 4,
deductionTypeId: 1,
deductionTypeTitle: 'TypeTitle2',
deductionExchangeTypeId: 4,
deductionExchangeTypeTitle: 'Exchange2',
wageTitle: 'wageTitle3',
},
{
id: 5,
deductionTypeId: 1,
deductionTypeTitle: 'TypeTitle2',
deductionExchangeTypeId: 5,
deductionExchangeTypeTitle: 'Exchange3',
wageTitle: 'wageTitle4',
},
{
id: 9,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle5',
},
{
id: 10,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle6',
},
{
id: 11,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle7',
},
{
id: 12,
deductionTypeId: 6,
deductionTypeTitle: 'TypeTitle1',
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: 'Exchange1',
wageTitle: 'wageTitle8',
},
];
const result = _(data)
.groupBy('deductionTypeTitle')
.mapValues((items) =>
_(items)
.groupBy('deductionExchangeTypeTitle')
.mapValues((items) =>
_(items)
.flatMap((item) => item.wageTitle)
.value(),
)
.value(),
)
.value();
// result:
// {
// TypeTitle1: {
// Exchange1: ['wageTitle1', 'wageTitle2', 'wageTitle5', 'wageTitle6', 'wageTitle7', 'wageTitle8'],
// },
// TypeTitle2: { Exchange2: ['wageTitle3'], Exchange3: ['wageTitle4'] },
// }
``
This may be one possible solution to achieve the desired objective.
Code Snippet
If the UI is not needed, simply use the method: groupAndSort to obtain the desired array which will be sorted in the desired order.
const Thingy = ({data, ...props}) => {
const groupAndSort = arr => (
[...arr.map(x => ({...x}))]
.map(x => ({...x, l1: "", l2: "", l3: ""}))
.sort((a, b) => (
a.deductionTypeTitle === b.deductionTypeTitle
? a.deductionExchangeTypeTitle === b.deductionExchangeTypeTitle
? a.wageTitle === b.wageTitle
? 1
: a.wageTitle > b.wageTitle
? 1
: -1
: a.deductionExchangeTypeTitle > b.deductionExchangeTypeTitle
? 1
: -1
: a.deductionTypeTitle > b.deductionTypeTitle
? 1
: -1
))
.map(
(x, i, a) => {
if (i === 0) {
return ({
...x,
l1: x.deductionTypeTitle,
l2: x.deductionExchangeTypeTitle,
l3: x.wageTitle
})
} else {
const t = {...x};
if (x.deductionTypeTitle !== a[i-1].deductionTypeTitle) {
t.l1 = x.deductionTypeTitle
};
if (x.deductionExchangeTypeTitle !== a[i-1].deductionExchangeTypeTitle) {
t.l2 = x.deductionExchangeTypeTitle
};
if (x.wageTitle !== a[i-1].wageTitle) {
t.l3 = x.wageTitle
};
return t;
}
}
)
);
return(
<div>
<h4>Desired Display</h4>
{
groupAndSort(data)
.map(
({l1, l2, l3}) => (
<div>
<div>{l1}</div>
<div>    {l2}</div>
<div>        {l3}</div>
</div>
)
)
}
<br/><br/>
<h4>Sorted-Grouped Data-Array</h4>
{
JSON.stringify(groupAndSort(data))
}
</div>
);
};
const rawData = [{
id: 6,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle1"
}, {
id: 8,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle2"
}, {
id: 4,
deductionTypeId: 1,
deductionTypeTitle: "TypeTitle2",
deductionExchangeTypeId: 4,
deductionExchangeTypeTitle: "Exchange2",
wageTitle: "wageTitle3"
}, {
id: 5,
deductionTypeId: 1,
deductionTypeTitle: "TypeTitle2",
deductionExchangeTypeId: 5,
deductionExchangeTypeTitle: "Exchange3",
wageTitle: "wageTitle4"
}, {
id: 9,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle5"
}, {
id: 10,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle6"
}, {
id: 11,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle7"
}, {
id: 12,
deductionTypeId: 6,
deductionTypeTitle: "TypeTitle1",
deductionExchangeTypeId: 3,
deductionExchangeTypeTitle: "Exchange1",
wageTitle: "wageTitle8"
}];
ReactDOM.render(
<div>
<h3>DEMO - Sort And Group Data</h3>
<Thingy data={rawData} />
</div>,
document.getElementById("rd")
);
<div id="rd"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
Method: groupAndSort
First, deep-clone the array (so the original remains as-is)
This is done using [...arr.map(x => ({...x})] --> multiple ... spread operators
Now, add 3 props l1, l2, l3 to each array element
Use .sort checking to see if each of the levels match (ie, Type, Exchange, Wage Titles)
The nested ternary operators ?: may be replaced by if ... else if ... construct (if preferred)
Finally, .map one last time to populate the new props added (ie, l1, l2, l3)
The implicit return within the method groupAndSort returns the resulting array
JSX:
First, use .map to iterate the result
Render l1, l2, l3 in individual lines
Next, for reference use JSON.stringify to render the actual array returned from the method groupAndSort

Credit card checker with Luhn algorith javascript

I am currently working on codeacademy's 'Credit Card Checker' using Luhn algorithm, however my code is returning false on valid arrays(which should return). Could you help me resolve the issue?
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = arr => {
let totalSum = 0;
let revList = arr.reverse();
for (let i = 0; i < revList.length; i++) {
let calcAmount = revList[i];
if (i !== 0 && i%2 === 0) {
calcAmount = revList[i] * 2;
if (calcAmount > 9 ) {
calcAmount -= 9;
totalSum += calcAmount;
} else {
totalSum += calcAmount;
}
} else {
totalSum += revList[i];
}
}
return (totalSum%10 === 0 ? true : false);
};
console.log(validateCred(valid3))
console.log(validateCred(valid4))
console.log(validateCred(valid5))
A simple mistake, check if (i%2 === 1) {, algorithm needs to multiply 2 for every second elements
arr.reverse() is also bad idea, original array is changed.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = arr => {
let totalSum = 0;
let revList = arr.reverse();
for (let i = 0; i < revList.length; i++) {
let calcAmount = revList[i];
if (i%2 === 1) {
calcAmount = revList[i] * 2;
if (calcAmount > 9 ) {
calcAmount -= 9;
totalSum += calcAmount;
} else {
totalSum += calcAmount;
}
} else {
totalSum += revList[i];
}
}
return(totalSum%10 === 0 ? true : false);
};
batch.forEach(c => console.log(validateCred(c)));
Rewrite and fixed.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
function luhnCheck(num) {
let digit, j, len, odd = true, sum = 0
const digits = (num + '').split('').reverse()
for (j = 0, len = digits.length; j < len; j++) {
digit = parseInt(digits[j], 10)
if ((odd = !odd)) digit *= 2
if (digit > 9) digit -= 9
sum += digit
}
return sum % 10 === 0
}
batch.forEach((item) => {
let number = item.join('')
console.log(number, luhnCheck(number))
})
Ideally, you should pass it in as a string and let the function do the splitting (separation of concerns) as in a real app your want to do various things on the entered number before running luhn like.. cardTypeFromNumber (visa, maestro, dankort, mastercard, amex, dinersclub, discover, chinaunionpay (doesn't use luhn), jcb mostly have all different lengths you wouldn't want to run luhn until you validate the length and format), formatCardNumber, validateCardExpiry, validateCardCVC to name a few.
The Luhn algorithm is explained on Wikipedia. Others have answered the question, this is just a different implementation.
function luhnCheck(cardNumber) {
let nums = cardNumber.split('').reverse();
let checkValue = nums.shift();
let luhnSum = nums.reduce((sum, n, i) => {
let val = n*(i % 2? 1 : 2);
sum += val > 9? val - 9 : val;
return sum;
}, 0);
return checkValue == 10 - (luhnSum % 10);
}
['4539677908016808', // valid1
'5535766768751439', // valid2
'4532778771091795', // invalid1
'5795593392134643', // invalid2
'344801968305414', // mystery1
'5466100861620239', // mystery2
].forEach(cardNum =>
console.log(luhnCheck(cardNum))
);

Passing an array to a function parameter and getting values from nested array

I got stuck while practicing credit card checker practice.
My code:
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5]
// Add your functions below:
const validateCred = (array)=> {
let tempArrSub = []; //Holds values of the 9 subtracted from doubled elements bigger than 9
let tempArr = array; //Copies the values of the array passed into parameters
tempArr.pop();
tempArr.reverse();
for (let i = tempArr.length-1; i >=0; i-=2){ //Doubles every two elements from right to left
tempArr[i] *= 2;
}
for (let k = 0; k < tempArr.length; k++) { //Subtract 9 from every second element (right to left) if bigger than 9
if (tempArr[k] > 9){
tempArrSub.push(tempArr[k] - 9);
}
else {
tempArrSub.push(tempArr[k]);
}
}
let tempArrSum = 0;
for (let m = 0; m < tempArrSub.length; m++){ //Calculates the sum of all elements in the array
tempArrSum += tempArrSub[m];
}
tempArrSum += array.pop(); //Adds the last digit of initial array to the sum
if (tempArrSum % 10 === 0) { //Returns true if the sum is divisible by 10
return true;
}
else {
return false;
}
} //End Of Function
const findInvalidCards = (nestedArray) => {
let invalidCards = [];
let validCards = [];
for (let a = 0; a < nestedArray.length; a++){
if ( validateCred(nestedArray[a]) == true ) {
validCards.push(nestedArray[a]);
}
else {
invalidCards.push(nestedArray[a]);
}
}
console.log("Invalid cards: \n" + invalidCards);
console.log("Valid cards: \n" + validCards);
}
I checked all arrays one by one passing as an argument to validateCred() function. It's working and returning true or false for each credit card.
In order to automate process I wanted findInvalidCards() to find valid or invalid cards by calling validateCred() function inside itself and returning boolean value for each card.
Here I got stuck. Because it is returning true for the 1st card and false for the remaining cards. I've been playing with the code for the whole day, but I could not move forward. I rely on your help. Thanks in advance
I don't know if is it helpful to you or not. But I rewrite your code with an optimal way.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
isValidCard = (array) => {
let copy = [...array];
const last = copy.pop();
copy.reverse();
copy = copy.map((dig, i) => ((i % 2 === 0 ? dig * 2 : dig)));
copy = copy.map(dig => (dig > 9 ? dig - 9 : dig));
const sum = copy.reduce((acc, curr) => acc + curr);
return ((sum + last) % 10 === 0);
}
findInvalidCards = (array) => {
const validList = [];
const invalidList = [];
array.forEach(card => {
if (isValidCard(card)) {
validList.push(card);
} else {
invalidList.push(card);
}
});
console.log('valid cards', validList);
console.log('invalid cards', invalidList);
}
findInvalidCards(batch);
I think your issue is this line:
let tempArr = array; //Copies the values of the array passed into parameters
According to your comment you want to copy the array, but just assigning it to another variable does not copies it. In order to copy just so something like this:
let copy = array.slice(0);
/* or (will not work for large arrays) */
let copy = [...array];
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
const invalidCredit = [invalid1, invalid2, invalid3, invalid4, invalid5]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = (arr) => {
let reversedArr = arr.reverse();
let oddOccurrences = [];
reversedArr.forEach((value, i) => i % 2 ? oddOccurrences.push(value *= 2) : oddOccurrences.push(value));
const checking = oddOccurrences.map((greater) => (greater > 9 ? (greater -= 9) : greater));
const sum = checking.reduce((acc, num) => {
return acc + num
}, 0)
// Conditional check
if (sum % 10 === 0)
return 'valid'
else return 'invalid'
}
console.log(validateCred([4, 5, 3, 9, 6, 8, 9, 8, 8, 7, 7, 0, 5, 7, 9, 8]));
findInvalidCards = (newArr) => {
const invalidList = [];
const validList = [];
for (let i = 0; i < newArr.length; i += 15) {
// inner loop
for (let j = 0; j < newArr.length; j++) {
validateCred(newArr[j]) === 'invalid' ? invalidList.push(newArr[j]) : validList.push(newArr[j]);
}
};
console.log(invalidList)
}
findInvalidCards(batch);

how to concat two object arrays of different size by key using lodash

Stocks: [{
PRN: 1,
PID: 1,
Qty: 3,
SlNos: [1, 2, 3]
}, {
PRN: 1,
PID: 2,
Qty: 4,
SlNos: [10, 11, 12, 13]
}, {
PRN: 2,
PID: 1,
Qty: 3,
SlNos: [4, 5, 6]
}, {
PRN: 2,
PID: 2,
Qty: 4,
SlNos: [14, 15, 16, 17]
}]
I want this array as bellow with Lodash
Stocks: [{
PID: 1,
Qty: 6,
SlNos: [1, 2, 3, 4, 5, 6]
}, {
PID: 2,
Qty: 4,
SlNos: [10, 11, 12, 13, 14, 15, 16, 17]
}]
Here is a solution with _lodash:
var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
const result = _.reduce(stocks, (r, {PRN, ...c}) => {
let _c = _.find(r, {'PID': c.PID})
if(_c)
_c = _.mergeWith(_c, c, (ov, sv, k) => _.includes(['Qty','SlNos'], k) ? _.isArray(sv) ? (ov || []).concat(sv) : _.isNumber(sv) ? sv + (ov || 0) : sv : ov)
else
r.push(c)
return r
}, [])
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
We are using reduce with mergeWith (which is the main thing here really) plus a little bit of includes.
Here is a solution without lodash that will do the trick:
var stocks = [{ PRN: 1, PID: 1, Qty: 3, SlNos: [1, 2, 3] }, { PRN: 1, PID: 2, Qty: 4, SlNos: [10, 11, 12, 13] }, { PRN: 2, PID: 1, Qty: 3, SlNos: [4, 5, 6] }, { PRN: 2, PID: 2, Qty: 4, SlNos: [14, 15, 16, 17] }]
const result = stocks.reduce((r, c) => {
_c = r.find(x => x.PID === c.PID)
if (_c) {
_c.PID = c.PID
_c.Qty = _c.Qty + c.Qty
_c.SlNos = _c.SlNos ? _c.SlNos.concat(c.SlNos) : c.SlNos
} else {
r.push(!delete(c.PRN) || c)
}
return r
}, [])
console.log(result)
The idea is to use reduce and first find if we had already that object by PID if so sum the values if not insert to the final array. Since we are going through each record that logic does the trick in one loop.

Create a stacked percentage column

I have a collection of data like this :
var data = [
{"p301a":"10","p301b":"7","p301c":"7","p301d":"3","p301e":"8","p301f":"8","p301g":"8","p301h":"8","p301i":"8","p301j":"8","p301k":"8","p301l":"8","p301m":"8","p301n":"8","p301o":"8","age":"31-40 years","profesion":"2","position":"2"},
{"p301a":"5","p301b":"4","p301c":"4","p301d":"4","p301e":"4","p301f":"4","p301g":"4","p301h":"4","p301i":"4","p301j":"4","p301k":"4","p301l":"4","p301m":"4","p301n":"4","p301o":"4","age":"24-30 years","profesion":"2","position":"2"},
{"p301a":"8","p301b":"8","p301c":"3","p301d":"9","p301e":"9","p301f":"4","p301g":"9","p301h":"4","p301i":"2","p301j":"9","p301k":"4","p301l":"9","p301m":"4","p301n":"9","p301o":"9","age":"31-40 years","profesion":"1","position":"3"},
{"p301a":"3","p301b":"3","p301c":"3","p301d":"8","p301e":"9","p301f":"9","p301g":"8","p301h":"9","p301i":"9","p301j":"9","p301k":"8","p301l":"8","p301m":"3","p301n":"3","p301o":"3","age":"31-40 years","profesion":"1","position":"3"},
{"p301a":"6","p301b":"5","p301c":"5","p301d":"8","p301e":"7","p301f":"5","p301g":"6","p301h":"2","p301i":"6","p301j":"5","p301k":"7","p301l":"7","p301m":"4","p301n":"8","p301o":"3","age":"24-30 years","profesion":"1","position":"2"},
{"p301a":"8","p301b":"8","p301c":"4","p301d":"4","p301e":"4","p301f":"5","p301g":"4","p301h":"4","p301i":"4","p301j":"4","p301k":"4","p301l":"9","p301m":"9","p301n":"9","p301o":"4","age":"31-40 years","profesion":"2","position":"3"}
];
From the data I want to create a Stacked percentage column from highchartjs,
With the stipulation of each bar having the number of p301a = 1, p301a = 2 and so on up to 10.
I think it can be done using underscore.js, but I do not know how.
i want to create somthing like this
example
or i want to get data like this :
var xAxis: {
categories: ['a', 'b', 'c' ... 'o' ]
},
var series: [{
name: '1',
data: [5, 3, 4, 7, 2, 5, 9, 5, 8, 4, 5, 7, 8, 3, 4]
}, {
name: '2',
data: [2, 2, 3, 2, 1, 5, 9, 5, 8, 4, 5, 7, 8, 3, 4]
}, {
name: '3',
data: [3, 4, 4, 2, 5, 5, 9, 5, 8, 4, 5, 7, 8, 3, 4]
}, {
name: '4',
data: [3, 4, 4, 2, 5, 5, 9, 5, 8, 4, 5, 7, 8, 3, 4]
}, ... (until 10)]
Sorry for the english
Please help

Categories

Resources