Categorize similar transactions
Given a list of transactions, some transactions are categorized, some transactions are not categorized. Find similar transactions and categorize them if possible. Similar transactions have the same targetAccount and the amount difference is not greater than 1000 (for all currencies) from the originally categorized transaction. If an uncategorized transaction is similar to more than one transaction, it should take the category from the one with the smallest amount difference. Transactions that cannot be categorized should still be included in the returned list. The returned list should preserve the order of the original list.
categorizeSimilarTransactions(transactions)
Input You can assume that the transactions parameter will always be present and valid. list of transactions (Transaction[])
Output List of transactions(Transaction[]) with enhanced categorization if possible.
This is what a categorized transaction looks like:
{
id: "bfd6a11a-2099-4b69-a7bb-572d8436cf73",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -350,
currency: "EUR",
category: "eating_out",
time: "2021-03-12T12:34:00Z"
}
An uncategorized transaction does not have category property. This is what an uncategorized transaction looks like:
{
id: "0f0ffbf9-2e26-4f5a-a6c0-fcbd504002f8",
sourceAccount: "my_account",
targetAccount: "eating_out",
amount: -1900,
time: "2021-03-12T12:34:00Z"
}
The following two transactions are similar:
{
id: "bfd6a11a-2099-4b69-a7bb-572d8436cf73",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -350,
category: "eating_out",
time: "2021-03-12T12:34:00Z"
}
and
{
id: "a001bb66-6f4c-48bf-8ae0-f73453aa8dd5",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -620,
time: "2021-04-10T10:30:00Z"
}
Input
categorizeSimilarTransactions([
{
id: "a001bb66-6f4c-48bf-8ae0-f73453aa8dd5",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: 350,
time: "2021-04-10T10:30:00Z",
},
{
id: "bfd6a11a-2099-4b69-a7bb-572d8436cf73",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -150,
category: "eating_out",
time: "2021-03-12T12:34:00Z",
},
{
id: "6359091e-1187-471f-a2aa-81bd2647210f",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: 100,
category: "entertainment",
time: "2021-01-12T08:23:00Z",
},
{
id: "a8170ced-1c5f-432c-bb7d-867589a9d4b8",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -1690,
time: "2021-04-12T08:20:00Z",
},
]);
Expected Output
[
{
id: "a001bb66-6f4c-48bf-8ae0-f73453aa8dd5",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: 350,
category: "entertainment",
time: "2021-04-10T10:30:00Z",
},
{
id: "bfd6a11a-2099-4b69-a7bb-572d8436cf73",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -150,
category: "eating_out",
time: "2021-03-12T12:34:00Z",
},
{
id: "6359091e-1187-471f-a2aa-81bd2647210f",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: 100,
category: "entertainment",
time: "2021-01-12T08:23:00Z",
},
{
id: "a8170ced-1c5f-432c-bb7d-867589a9d4b8",
sourceAccount: "my_account",
targetAccount: "coffee_shop",
amount: -1690,
time: "2021-04-12T08:20:00Z",
},
];
I could find a solution but it's a brute-force approach & not efficient. Is there any other solution with less time complexity may be O(n) or O(log(n))/O(nlog(n)) which is easy to read & understand
const categorizeSimilarTransactions = (transactions) => {
if (!(Array.isArray(transactions) && transactions.length)) return [];
const categorizedTransactions = transactions.filter(t => t.category);
const uncategorizedTransactions = transactions.filter(t => !t.category);
let lowestDiff;
uncategorizedTransactions.forEach(uncategorizedTransaction => {
lowestDiff = Math.min();
categorizedTransactions.forEach(cat => {
if (cat.targetAccount === uncategorizedTransaction.targetAccount) {
lowestDiffComp = Math.abs(cat.amount - uncategorizedTransaction.amount);
if (lowestDiffComp < lowestDiff && lowestDiffComp < 1000) {
lowestDiff = lowestDiffComp;
uncategorizedTransaction.category = cat.category;
}
}
})
});
const merged = [...categorizedTransactions, ...uncategorizedTransactions];
const orderIds = transactions.map(transaction => transaction.id);
merged.sort((a, b) => {
return orderIds.indexOf(a.id) - orderIds.indexOf(b.id);
})
return merged;
};
do you know?
how many words do you know