30 May 2025 | Challenge 323 |
Tax Steps
Task 1: Increment Decrement
Submitted by: Mohammad Sajid Anwar
You are given a list of operations.
Write a script to return the final value after performing the given operations in order. The initial value is always 0.
Possible Operations:
++x or x++: increment by 1
--x or x--: decrement by 1
Example 1
Input: @operations = ("--x", "x++", "x++")
Output: 1
Operation "--x" => 0 - 1 => -1
Operation "x++" => -1 + 1 => 0
Operation "x++" => 0 + 1 => 1
Example 2
Input: @operations = ("x++", "++x", "x++")
Output: 3
Example 3
Input: @operations = ("x++", "++x", "--x", "x--")
Output: 0
Operation "x++" => 0 + 1 => 1
Operation "++x" => 1 + 1 => 2
Operation "--x" => 2 - 1 => 1
Operation "x--" => 1 - 1 => 0
Solution
Matching each operation against a regex that:
- looks ahead a the start of the string for of length 3
- followed by an optional
x
- followed by two
-
or+
signs, capturing the first - followed by an optional
x
at the end of the string
Prepending the extracted sign from the matching operation to a 1
to produce a valid number and take the sum over these gives the requested result.
Any operation not contained in the given set will be ignored as it gives a false
regex matching result that has a numerical value of 0
.
use strict;
use warnings;
use List::Util 'sum0';
sub inc_dec {
sum0 map /^(?=.{3}$)x?([-+])\1x?$/ && "${1}1", @_
}
See the full solution to task 1.
Task 2: Tax Amount
Submitted by: Mohammad Sajid Anwar
You are given an income amount and tax brackets.
Write a script to calculate the total tax amount.
Example 1
Input: $income = 10, @tax = ([3, 50], [7, 10], [12,25])
Output: 1.65
1st tax bracket upto 3, tax is 50%.
2nd tax bracket upto 7, tax is 10%.
3rd tax bracket upto 12, tax is 25%.
Total Tax => (3 * 50/100) + (4 * 10/100) + (3 * 25/100)
=> 1.50 + 0.40 + 0.75
=> 2.65
Example 2
Input: $income = 2, @tax = ([1, 0], [4, 25], [5,50])
Output: 0.25
Total Tax => (1 * 0/100) + (1 * 25/100)
=> 0 + 0.25
=> 0.25
Example 3
Input: $income = 0, @tax = ([2, 50])
Output: 0
Solution
With a little pre-processing of the tax brackets, the final tax calculation can be simplified.
We are given \(n\) pairs \((u_i, t_i) \text{ for } 1 \le i \le n\) of upper bracket limits \(u_i\) and the corresponding tax rate \(t_i\). Presuming the the brackets to be sorted by ascending limits and converting percentages to floating point factors.
Let us consider \(n + 1\) triplets \((l_i, \hat{t}_i, c_i) \text{ for } 0 \le i \le n\) instead, where \(l_i\) are the lower bracket limits, \(\hat{t}_i\) are the tax rates and \(c_i\) are the cumulative sums over the maximum tax over all brackets. These values are defined as:
\[\begin{align*} l_i &= \begin{cases} 0& \text{if $i = 0$},\\ u_i& \text{if $i > 0$} \end{cases}\\ \hat{t}_i &= \begin{cases} t_{i+1}& \text{if $i < n$},\\ 0& \text{if $i = n$} \end{cases}\\ c_i &= \begin{cases} 0& \text{if $i = 0$},\\ c_{i-1} + (l_i - l_{i-1})t_i& \text{if $i >0$} \end{cases} \end{align*}\]This new configuration has a final pseudo-bracket without upper limit and a tax rate of zero.
After identifying the bracket \(k\) a given income \(I\) belongs to as \(k = \max\,\{i | l_i \le I\}\), the total tax \(T\) can be calculated as
\[T = c_k + \hat{t}_k (I - l_k)\]The index \(k\) can be found with a binary search using PDL::Primitive
’s
vsearch_bin_inclusive
.
Multiple calculations based on the same tax schema can be done using the same pre-processed data.
sub tax_pp
pre-processes the given pairs returning the described triplets, which need to be given as the second argument to sub tax_amount
.
use strict;
use warnings;
use PDL;
use PDL::NiceSlice;
use experimental 'signatures';
sub tax_pp {
my $tax = pdl @_;
$tax(1) /= 100;
my $low = pdl(0)->append($tax((0)));
cat $low,
$tax((1))->append(pdl(0)),
pdl(0)->append((($low(1:-1) - $low(0:-2)) * $tax((1)))->cumusumover);
}
sub tax_amount ($income, $tp) {
my $tax = $tp(vsearch_bin_inclusive($income, $tp(,(0)));-);
sclr $tax(2) + $tax(1) * ($income - $tax(0));
}
See the full solution to task 2.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.