# Consecutive, but Maybe Not Final **Challenge 325 solutions in Perl by Matthias Muth** ## Task 1: Consecutive One > 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** > > ```text > Input: @binary = (0, 1, 1, 0, 1, 1, 1) > Output: 3 >``` > >**Example 2** > >```text > Input: @binary = (0, 0, 0, 0) > Output: 0 > ``` > > **Example 3** > > ```text >Input: @binary = (1, 0, 1, 0, 1, 1) > Output: 2 > ``` For this task, first thing I do is to walk through the array and assign to each element the number of `1`s that have been seen since the last `0`. Like this: ```text @binary: 0 1 1 0 1 1 1 | | | | | | | # of ones: 0 1 2 0 1 2 3 ``` To do that, I need to carry over the current number of `1`s from position to position. This makes it a perfect use case for the `reductions` function (from `List::Util`). In its code block, the `$a` variable is the result for the previous element, and `$b` is the current element. That makes this type of 'conditional counting' very easy: ```perl reductions { $b ? ++$a : 0 } @binary ``` Now it's very simple to find the maximum number of consecutive `1`s: just apply the `max` function on the result. Which makes this tasks solution a very nice and simple one-line-of-code function: ```perl sub consecutive_one( @binary ) { return max( reductions { $b ? ++$a : 0 } @binary ); } ``` ## Task 2: Final Price > 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** > > ```text > 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** > >```text > Input: @prices = (1, 2, 3, 4, 5) > Output: (1, 2, 3, 4, 5) > ``` > > **Example 3** > > ```text >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 > ``` My solution for this task is short , and simple enough, but I don't really like it.
I couldn't come up with a way to avoid the 'almost quadratic' behavior of walking through the whole rest of the list to find a discount for *every* entry in the list, that's why I am not really happy. But this is what I have: I use `map` to map the item prices from the `@prices` array to the final prices to be returned. The final price is the item price minus a possible discount, and for getting that discount, I use `first` to walk through the rest of the array to find the next item price that is lower than or equal to the current one. ```perl use v5.36; use List::Util qw( first ); sub final_price( @prices ) { return map { my $price = $prices[$_]; my $discount = first { $_ <= $price } @prices[ $_ + 1 .. $#prices ]; $price - ( $discount // 0 ); } keys @prices; } ``` As I said, simple enough, but I guess there must be a better algorithmic solution ... #### **Thank you for the challenge!**