Last active
November 30, 2020 02:00
-
-
Save camisetags/10b5656411c683646193acdbb606535e to your computer and use it in GitHub Desktop.
transactionChallenge
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// from codepad | |
var Mocha = require('mocha') | |
var mocha = new Mocha() | |
mocha.suite.emit('pre-require', this, 'solution', mocha) | |
var assert = require("chai").assert; | |
var transacts = [ | |
{ | |
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 transactsExpects = [ | |
[ | |
{ | |
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" | |
} | |
] | |
]; | |
describe("findDuplicateTransactions()", function() { | |
it("returns empty array if there are no transactions", function() { | |
assert.deepEqual(findDuplicateTransactions([]), []); | |
}); | |
it("returns correctness transactions", function() { | |
assert.deepEqual(findDuplicateTransactions(transacts), transactsExpects); | |
}); | |
}); | |
// Codepad again | |
mocha.run() | |
function groupBy( array , f ){ | |
var groups = {}; | |
array.forEach( function( o ){ | |
var group = JSON.stringify( f(o) ); | |
console.log(group); | |
groups[group] = groups[group] || []; | |
groups[group].push( o ); | |
}); | |
return Object.keys(groups).map( function( group ) { | |
return groups[group]; | |
}) | |
} | |
const findDuplicateTransactions = ( transactions = []) => { | |
var result = groupBy(transactions, function(item){ | |
return [item.amount, item.sourceAccount, item.targetAccount, item.category]; | |
}); | |
return result.map((transactionList) => { | |
const convertedTransactions = transactionList | |
.map(transaction => ({ | |
...transaction, | |
time: Date.parse(transaction.time)/1000 | |
})) | |
.sort((prev, curr) => prev.time - curr.time) | |
.reduce((acc, cur, index) => { | |
const lastPos = acc[acc.length - 1] || cur; | |
return cur.time - lastPos.time < 60 || index === 0 | |
? [...acc, cur] | |
: [...acc]; | |
}, []) | |
.map((transaction) => ({ | |
...transaction, | |
time: new Date(transaction.time * 1000).toISOString() | |
})); | |
return convertedTransactions; | |
}); | |
} | |
console.log("############"); | |
console.log(findDuplicateTransactions(transacts)); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Balance by category | |
//Calculate the balance in a specific category within the specified time period. | |
//getBalanceByCategoryInPeriod(transactionsList, category, startTime, endTime) | |
//Input | |
//You can assume that all parameters will always be present and valid. | |
//list of transactions (Transaction[]) | |
//category (String) | |
//start time (inclusive) (Date) | |
//end time (exclusive) (Date) | |
//Output | |
//Total balance (Number) | |
//Negative number means money spent. | |
//Remember, this is what a transaction looks like: | |
//{ | |
// id: 123, | |
// sourceAccount: 'my_account', | |
// targetAccount: 'coffee_shop', | |
// amount: -30, | |
// category: 'eating_out', | |
// time: '2018-03-12T12:34:00Z' | |
//} | |
// from codepad | |
var Mocha = require('mocha') | |
var mocha = new Mocha() | |
mocha.suite.emit('pre-require', this, 'solution', mocha) | |
var assert = require("chai").assert; | |
var transacts = [ { | |
id: 1, | |
sourceAccount: 'my_account', | |
targetAccount: 'coffee_shop', | |
amount: -30, | |
category: 'eating_out', | |
time: '2018-03-12T12:34:00Z' | |
}, | |
{ | |
id: 4, | |
sourceAccount: 'my_account', | |
targetAccount: 'coffee_shop', | |
amount: -60, | |
category: 'eating_out', | |
time: '2018-09-16' | |
}, | |
{ | |
id: 2, | |
sourceAccount: 'my_account', | |
targetAccount: 'coffee_shop', | |
amount: 300, | |
category: 'beauty', | |
time: '2018-09-15T12:34:00Z' | |
}, | |
{ | |
id: 3, | |
sourceAccount: 'my_account', | |
targetAccount: 'coffee_shop', | |
amount: 21, | |
category: 'beauty', | |
time: '2018-10-18T11:34:00Z' | |
}, | |
]; | |
function setEndDate(date) { | |
date = date ? new Date(date) : new Date(); | |
if (date.getUTCHours() <= 0){ | |
date.setDate(date.getDate() + 1); | |
date.setHours(0); | |
date.setMinutes(0); | |
} | |
return Date.parse(date); | |
} | |
function getBalanceByCategoryInPeriod(transactions = [], category, start, end) { | |
start = Date.parse(start); | |
end = setEndDate(end); | |
const trans = transactions | |
.map((transaction) => { | |
const { id, sourceAccount, targetAccount, ...cleanTransaction } = transaction; | |
return { | |
...cleanTransaction, | |
time: Date.parse(cleanTransaction.time) | |
}; | |
}).filter((transaction) => | |
!!end | |
? (transaction.category === category && | |
(transaction.time >= start && transaction.time <= end)) | |
: (transaction.category === category && transaction.time >= start) | |
).reduce((totalBalance, transaction) => totalBalance + transaction.amount, 0); | |
return trans; | |
} | |
describe("getBalanceByCategoryInPeriod()", () => { | |
it("returns 0 if there are no transactions", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
[], | |
"groceries", | |
new Date("2018-03-01"), | |
new Date("2018-03-31") | |
), | |
0 | |
); | |
}); | |
it("returns 321 with beauty category", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
transacts, | |
"beauty", | |
new Date("2018-09-15"), | |
new Date("2018-10-18") | |
), | |
321 | |
); | |
}); | |
it("returns 321 with beauty category without end date", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
transacts, | |
"beauty", | |
new Date("2018-09-15") | |
), | |
321 | |
); | |
}); | |
it("returns -90 with eating_out category", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
transacts, | |
"eating_out", | |
new Date("2018-02-11"), | |
new Date("2018-09-16") | |
), | |
-90 | |
); | |
}); | |
it("returns 0 with random values", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
[{ aaa: 'aaa', bbb: 'bbb' }], | |
"beauty", | |
new Date("2018-09-15") | |
), | |
0 | |
); | |
}); | |
it("includes transactions on start and excludes transactions on end", () => { | |
assert.equal( | |
getBalanceByCategoryInPeriod( | |
transacts, | |
"beauty", | |
new Date("2018-02-11"), | |
new Date("2020-09-16") | |
), | |
321 | |
); | |
}); | |
}); | |
describe("setEndDate()", () => { | |
it("Return date complete datetime ", () => { | |
assert.equal( | |
setEndDate('2018-03-12T12:34:00Z'), | |
'1520858040000' | |
); | |
}); | |
it("return date without time", () => { | |
assert.equal( | |
setEndDate("2018-05-10"), | |
1525996800000 | |
); | |
}); | |
it("Return a date without a param", () => { | |
assert.isNumber( | |
setEndDate("") | |
); | |
}); | |
}) | |
// Codepad again | |
mocha.run() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment