Sometimes when a customer is charged, there is a duplicate transaction created. We need to find those transactions so that they can be dealt with. Everything about the transaction should be identical, except the transaction id and the time at which it occurred, as there can be up to a minute delay.
i need to Find all transactions that have the same sourceAccount, targetAccount, category, amount, and the time difference between each consecutive transaction is less than 1 minute.
I'd been trying looping the array and using map to create a new array, but i don't know how to match the array without providing a reference for the value, due the values in the array are dynamical i can't know the value.
var transac = [
{
id: 3,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:34:30.000Z'
},
{
id: 1,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:33:00.000Z'
},
{
id: 6,
sourceAccount: 'A',
targetAccount: 'C',
amount: 250,
category: 'other',
time: '2018-03-02T10:33:05.000Z'
},
{
id: 4,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:36:00.000Z'
},
{
id: 2,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:33:50.000Z'
},
{
id: 5,
sourceAccount: 'A',
targetAccount: 'C',
amount: 250,
category: 'other',
time: '2018-03-02T10:33:00.000Z'
}
];
expected:
[
[
{
id: 1,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:33:00.000Z"
},
{
id: 2,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:33:50.000Z"
},
{
id: 3,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:34:30.000Z"
}
],
[
{
id: 5,
sourceAccount: "A",
targetAccount: "C",
amount: 250,
category: "other",
time: "2018-03-02T10:33:00.000Z"
},
{
id: 6,
sourceAccount: "A",
targetAccount: "C",
amount: 250,
category: "other",
time: "2018-03-02T10:33:05.000Z"
}
]
];
Sometimes when a customer is charged, there is a duplicate transaction created. We need to find those transactions so that they can be dealt with. Everything about the transaction should be identical, except the transaction id and the time at which it occurred, as there can be up to a minute delay.
i need to Find all transactions that have the same sourceAccount, targetAccount, category, amount, and the time difference between each consecutive transaction is less than 1 minute.
I'd been trying looping the array and using map to create a new array, but i don't know how to match the array without providing a reference for the value, due the values in the array are dynamical i can't know the value.
var transac = [
{
id: 3,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:34:30.000Z'
},
{
id: 1,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:33:00.000Z'
},
{
id: 6,
sourceAccount: 'A',
targetAccount: 'C',
amount: 250,
category: 'other',
time: '2018-03-02T10:33:05.000Z'
},
{
id: 4,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:36:00.000Z'
},
{
id: 2,
sourceAccount: 'A',
targetAccount: 'B',
amount: 100,
category: 'eating_out',
time: '2018-03-02T10:33:50.000Z'
},
{
id: 5,
sourceAccount: 'A',
targetAccount: 'C',
amount: 250,
category: 'other',
time: '2018-03-02T10:33:00.000Z'
}
];
expected:
[
[
{
id: 1,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:33:00.000Z"
},
{
id: 2,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:33:50.000Z"
},
{
id: 3,
sourceAccount: "A",
targetAccount: "B",
amount: 100,
category: "eating_out",
time: "2018-03-02T10:34:30.000Z"
}
],
[
{
id: 5,
sourceAccount: "A",
targetAccount: "C",
amount: 250,
category: "other",
time: "2018-03-02T10:33:00.000Z"
},
{
id: 6,
sourceAccount: "A",
targetAccount: "C",
amount: 250,
category: "other",
time: "2018-03-02T10:33:05.000Z"
}
]
];
Share
Improve this question
asked Jan 20, 2019 at 19:41
alexmorgan.cralexmorgan.cr
3007 silver badges21 bronze badges
2
- Can you show us your loop that you are using to go over your array? Even though you can't see them, arrays always have an index (0,1,2 etc.) – Laurens Commented Jan 20, 2019 at 19:50
- 1 What do you want to happen when you have similar transactions with only a time difference of 55 seconds, but there are 100 of them and they are all 55 seconds apart, making the last more than one hour later than the first in that chain. – trincot Commented Jan 20, 2019 at 19:55
3 Answers
Reset to default 7I would create a posed key for the key fields and translate the time to a number of milliseconds and then sort by those two elements. In a second step group those entries that have the same key and are at most 1 minute apart:
var transac = [{id: 3,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:34:30.000Z'},{id: 1,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:33:00.000Z'},{id: 6,sourceAccount: 'A',targetAccount: 'C',amount: 250,category: 'other',time: '2018-03-02T10:33:05.000Z'},{id: 4,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:36:00.000Z'},{id: 2,sourceAccount: 'A',targetAccount: 'B',amount: 100,category: 'eating_out',time: '2018-03-02T10:33:50.000Z'},{id: 5,sourceAccount: 'A',targetAccount: 'C',amount: 250,category: 'other',time: '2018-03-02T10:33:00.000Z'}];
const result = transac.map(t => ({
key: JSON.stringify([t.sourceAccount, t.targetAccount, t.amount, t.category]),
epoch: Date.parse(t.time),
t
})).sort((a,b) =>
a.key.localeCompare(b.key) || a.epoch - b.epoch || a.t.id - b.t.id
).reduce(([acc, prev], curr) => {
if (!prev || curr.key != prev.key || curr.epoch - prev.epoch > 60000) acc.push([]);
acc[acc.length-1].push(curr.t);
return [acc, curr];
}, [[]])[0];
console.log(result);
Following up on a ment below, the above result includes all transactions. The ones that have "duplicates" (according to the definition in the question) are grouped together with their duplicates in sub arrays; those that do not have such duplicates appear alone in their own sub arrays.
So to only get the duplicates, add the appropriate filter:
const duplicates = result.filter(a => a.length > 1);
Solution 1 Solution 1 naive approach - Data is sorted by date and all duplicates are one after the other.
var first = reducedTransac.shift();
if (!first) {
return [];
}
var reducedTransac = transac.reduce(function(approvedTransac, currentTrans) {
var lastTrans = approvedTransac[approvedTransac.length - 1];
//You'll need to write timeDiff yourself :-)
var isTimeDiffLessThanSecond = timeDiff(lastTrans.date, currentTrans.time) >= 1;
// Also, this can be done in many other ways, I've taken the check out of the if for code clarity, if performance is important move them inside the if...
var isSameSourceAccount = lastTrans.sourceAccount === currentTrans.sourceAccount;
var isSameTargetAccount = lastTrans.targetAccount === currentTrans.targetAccount;
var isSameCategory = lastTrans.category === currentTrans.category;
var isSameAmount = lastTrans.amount === currentTrans.amount;
if (isTimeDiffLessThanSecond && isSameSourceAccount && isSameTargetAccount && isSameCategory && isSameAmount) {
return approvedTransac;
}
approvedTransac.push(currentTrans);
return approvedTransac;
}, [first]);
Solution 2 No knowledge of input order
var first = reducedTransac.shift();
if(!first) {
return [];
}
var transacByTimeGroupedBy = transac.reduce(function(transGroupedByTime, currentTrans) {
var lastTransTimeGB = approvedTransac[approvedTransac.length - 1];
var lastTrans = lastTransTimeGB[lastTransTimeGB.length - 1];
//You'll need to write timeDiff yourself :-)
var isTimeDiffLessThanSecond = timeDiff(lastTrans.date, currentTrans.time) >= 1;
if(isTimeDiffLessThanSecond) {
approvedTransac[approvedTransac.length - 1].push(lastTrans);
} else {
approvedTransac.concat([lastTrans])
}
return approvedTransac;
}, [[first]]);
transacByTimeGroupedBy.map(function(transactions){
var first = transactions.shift();
if(!first) {
return [];
}
return transactions.reduce(function(approvedTransac, currentTrans) {
var lastTrans = approvedTransac[approvedTransac.length - 1];
var isSameSourceAccount = lastTrans.sourceAccount === currentTrans.sourceAccount;
var isSameTargetAccount = lastTrans.targetAccount === currentTrans.targetAccount;
var isSameCategory = lastTrans.category === currentTrans.category;
var isSameAmount = lastTrans.amount === currentTrans.amount;
if(isSameSourceAccount && isSameTargetAccount && isSameCategory && isSameAmount) {
return approvedTransac;
}
approvedTransac.push(currentTrans);
return approvedTransac;
}, [first]);
})
Then you just need to flatten the last array.
The code is not tested by should be very close to what you need.
You can use something like this:
var found=false, output=[], transac = [ { id: 3, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:34:30.000Z' }, { id: 1, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:00.000Z' }, { id: 6, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:05.000Z' }, { id: 4, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:36:00.000Z' }, { id: 2, sourceAccount: 'A', targetAccount: 'B', amount: 100, category: 'eating_out', time: '2018-03-02T10:33:50.000Z' }, { id: 5, sourceAccount: 'A', targetAccount: 'C', amount: 250, category: 'other', time: '2018-03-02T10:33:00.000Z' } ];
for(i=0;i<transac.length;i++){
j_for:for(j=0;j<output.length;j++){
for(k=0;k<output[j].length;k++){
if(transac[i].sourceAccount==output[j][k].sourceAccount&&transac[i].targetAccount==output[j][k].targetAccount&&transac[i].category==output[j][k].category&&transac[i].amount==output[j][k].amount&&new Date(transac[i].time).getTime()+60000>new Date(output[j][k].time).getTime()&&new Date(transac[i].time).getTime()-60000<new Date(output[j][k].time).getTime()){output[j].push(transac[i]);found=true;break j_for}
}
}
if(!found){output.push([transac[i]])}
found=false
}
console.log(output)
I hope that this will help you!
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744268418a4565977.html
评论列表(0条)