This is my response to The Weekly Challenge #323.
++x
or x++
: increment by 1
--x
or x--
: decrement by 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
#! /usr/bin/env raku
unit sub MAIN (*@operations where @operations.elems > 0 # [1]
&& all(@operations) eq any('++x', 'x++', '--x', 'x--'), # [1a]
:v(:$verbose));
my %val = ( '++x' => 1, 'x++' => 1, '--x' => -1, 'x--' => -1 ); # [2]
my @val = @operations.map({ %val{$_} }); # [3]
say ": Values: { @val.join(", ") }" if $verbose;
say @val.sum; # [4]
[1] A slurpy array, with at least one element. The values must be one of the four legal operations.
[2] A hash mapping the operations to the values they represent.
[3] Use map
to convert each operation to the value.
See docs.raku.org/routine/map for more information about map
.
[4] Add the values together with sum
, and print the result.
See docs.raku.org/routine/sum for more information about sum
.
Running it:
$ ./increment-decrement -- "--x" "x++" "x++"
1
$ ./increment-decrement "x++" "++x" "x++"
3
$ ./increment-decrement "x++" "++x" "--x" "x--"
0
Looking good.
With verbose mode:
$ ./increment-decrement -v -- "--x" "x++" "x++"
: Values: -1, 1, 1
1
$ ./increment-decrement -v "x++" "++x" "x++"
: Values: 1, 1, 1
3
$ ./increment-decrement -v "x++" "++x" "--x" "x--"
: Values: 1, 1, -1, -1
0
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
The program iterates over the brackets. It calculates the income and tax for each one, adding the bracket tax to the total tax, and subtracting the bracket income from the total income. It stops when it has run out of income to tax, even if we have additional brackets.
File: tax-amount
unit sub MAIN (UInt $income is copy, # [1]
*@tax-brackets where @tax-brackets.elems > 0, # [2]
:v(:$verbose));
my @tax = @tax-brackets>>.words; # [3]
my @limits = @tax[*;0]; # [4]
my @percents = @tax[*;1]; # [5]
die "Overlapping brackets" unless [<] @limits; # [6]
die "Wrong percentage values (0..100 only)"
unless all(@percents) ~~ Numeric # [7]
&& all(@percents) >= 0 # [7a]
&& all(@percents) <= 100; # [7b]
my $i = 0; # [8]
my $tax = 0; # [9]
for @tax -> ($at, $pct) # [10]
{
last if $income <= 0; # [11]
my $bracket = $at - $i; # [12]
my $add = min($bracket, $income) * $pct / 100; # [13]
say ": Add [{ $i +1 } .. $at]: $bracket @ $pct% = $add" if $verbose;
$i = $at; # [14]
$tax += $add; # [15]
$income -= $bracket; # [16]
}
say $tax; # [17]
[1]
The income as an unsigned integer, i.e. zero and above. Note the
is copy
, so that we can change it (in [16]).
See docs.raku.org/routine/UInt for more information about UInt
.
See docs.raku.org/type/Parameter#method_copy for more information about is copy
.
[2] A slurpy array of tax brackets, with at least one element. Each value is the limit and percentage, separated by a space.
[3] Unwrap the tax brackets. This gives a two dimentional array, as in the examples.
[4] Get the limits, the first element in the subarrays.
[5] Get the percentages, the second element in the subarrays.
[6] Ensure that the limits come in an
orderly fashion, using the Reduction Metaoperator []
in combination
with <
.
See
docs.raku.org/language/operators#Reduction_metaoperators for more
information about the Reduction Metaoperator []
.
[7] Ensure that the percentage values are between 0 and 100, both included.
[8] The current starting point, in monetary units.
[9] The total tax to pay will end up here.
[10] Iterate over the brackets, assigning the two subarray parts to individial variables.
[11] Exit the loop if we have no more income to tax.
[12] The taxable income in this bracket.
[13] The amount of tax to add, by applying the percentage. Note that we have to tax the amount only, so stop if we run out of taxable income.
[14] The start of the next bracket, ready for the next iteration.
[15] Add the tax for this bracket to the total.
[16] Subract the income taxed in this bracet, ready for the next iteration.
[17] Print the result.
Running it:
$ ./tax-amount 10 "3 50" "7 10" "12 25"
2.65
$ ./tax-amount 2 "1 0" "4 25" "5 50"
0.25
$ ./tax-amount 0 "2 50"
0
Looking good.
With verbose mode:
$ ./tax-amount -v 10 "3 50" "7 10" "12 25"
: Add [1 .. 3]: 3 @ 50% = 1.5
: Add [4 .. 7]: 4 @ 10% = 0.4
: Add [8 .. 12]: 5 @ 25% = 0.75
2.65
$ ./tax-amount -v 2 "1 0" "4 25" "5 50"
: Add [1 .. 1]: 1 @ 0% = 0
: Add [2 .. 4]: 3 @ 25% = 0.25
0.25
$ ./tax-amount -v 0 "2 50"
0
And that's it.