The Bear's Den

Enter at your own risk

Consecutive Discounts

Task 1: Consecutive One

Submitted by: Mohammad Sajid Anwar


You are given a binary array containing only 0 or/and 1.

Write a script to find out the maximum consecutive 1 in the given array.

Example 1

Input: @binary = (0, 1, 1, 0, 1, 1, 1)
Output: 3

Example 2

Input: @binary = (0, 0, 0, 0)
Output: 0

Example 3

Input: @binary = (1, 0, 1, 0, 1, 1)
Output: 2

Solution

This task can easily generalized to arrays containing any integers. Then we find the maximum consecutive repetitions of the same integer in the array.

Taking the maximum run length from non-zero values. As max returns BAD for an empty ndarray, this has to be converted to zero.

use strict;
use warnings;
use PDL;

sub max_consec {
    my ($count, $val) = long(@_)->rle;
    $count->where($val)->max->setbadtoval(0);
}

See the full solution to task 1.

Task 2: Final Price

Submitted by: Mohammad Sajid Anwar


You are given an array of item prices.

Write a script to find out the final price of each items in the given array.

There is a special discount scheme going on. If there’s an item with a lower or equal price later in the list, you get a discount equal to that later price (the first one you find in order).

Example 1

Input: @prices = (8, 4, 6, 2, 3)
Output: (4, 2, 4, 2, 3)

Item 0:
The item price is 8.
The first time that has price <= current item price is 4.
Final price = 8 - 4 => 4

Item 1:
The item price is 4.
The first time that has price <= current item price is 2.
Final price = 4 - 2 => 2

Item 2:
The item price is 6.
The first time that has price <= current item price is 2.
Final price = 6 - 2 => 4

Item 3:
The item price is 2.
No item has price <= current item price, no discount.
Final price = 2

Item 4:
The item price is 3.
Since it is the last item, so no discount.
Final price = 3

Example 2

Input: @prices = (1, 2, 3, 4, 5)
Output: (1, 2, 3, 4, 5)

Example 3

Input: @prices = (7, 1, 1, 5)
Output: (6, 0, 1, 5)

Item 0:
The item price is 7.
The first time that has price <= current item price is 1.
Final price = 7 - 1 => 6

Item 1:
The item price is 1.
The first time that has price <= current item price is 1.
Final price = 1 - 1 => 0

Item 2:
The item price is 1.
No item has price <= current item price, so no discount.
Final price = 1

Item 3:
The item price is 5.
Since it is the last item, so no discount.
Final price = 5

Solution

Let’s solve example 1 from the task step by step in the PDL shell.

Create an ndarray from the prices:

pdl> do_print 1
1
pdl> $price = pdl 8, 4, 6, 2, 3
[8 4 6 2 3]

Identify the positions where a price is not higher than each given price:

pdl> $le = $price <= $price->dummy(0)

[
 [1 1 1 1 1]
 [0 1 0 1 1]
 [0 1 1 1 1]
 [0 0 0 1 0]
 [0 0 0 1 1]
]

Identify the positions following each price:

pdl> $after = sequence($price) > sequence($price)->dummy(0)

[
 [0 1 1 1 1]
 [0 0 1 1 1]
 [0 0 0 1 1]
 [0 0 0 0 1]
 [0 0 0 0 0]
]

Identify the positions of not higher prices following each price:

pdl> $mask = $le & $after

[
 [0 1 1 1 1]
 [0 0 0 1 1]
 [0 0 0 1 1]
 [0 0 0 0 0]
 [0 0 0 0 0]
]

Find the prices on the found positions:

pdl> $discounts = $mask * $price

[
 [0 4 6 2 3]
 [0 0 0 2 3]
 [0 0 0 2 3]
 [0 0 0 0 0]
 [0 0 0 0 0]
]

Find the first nonzero entry in each row:

pdl> $discount = $discounts->firstnonzeroover
[4 2 2 0 0]

Subtract the discount from the price:

pdl> $price - $discount
[4 2 4 2 3]

Put everything together:

use strict;
use warnings;
use PDL;

sub final_price {
    my $price = pdl @_;
    $price - (
        (($price <= $price->dummy(0)) &
            (sequence($price) > sequence($price)->dummy(0))) * $price
    )->firstnonzeroover;
}

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.