Peter
Peter Campbell Smith

Product lines

Weekly challenge 267 — 29 April 2024

Week 267 - 29 Apr 2024

Task 1

Task — Product sign

You are given an array of @ints. Write a script to find the sign of product of all integers in the given array. The sign is 1 if the product is positive, -1 if the product is negative and 0 if product is zero.

Examples


Example 1
Input: @ints = (-1, -2, -3, -4, 3, 2, 1)
Output: 1

The product -1 x -2 x -3 x -4 x 3 x 2 x 1 => 144 > 0

Example 2
Input: @ints = (1, 2, 0, -2, -1)
Output: 0

The product 1 x 2 x 0 x -2 x -1 => 0

Example 3
Input: @ints = (-1, -1, 1, -1, 2)
Output: -1

The product -1 x -1 x 1 x -1 x 2 => -2 < 0

Analysis

There are a number of ways of performing this task. Let's start with the obvious one (method 1):

$product *= $_ for @ints;
say qq[Output1: ] . 
	($product ? $product / abs($product) : 0);

So that's multiply the numbers together and if the product is zero, output that, or else divide the product by its absolute value and output that.

That works for the examples given, but:

  • we could stop the multiplication if we find a zero, as no subsequent number will make the product non-zero,
  • If @ints contains some big numbers we could quickly exceed Perl's largest integer
  • multiplication is moderately expensive, and we don't actually need the product.

So here's method 2.

Set $result = 1, loop for $int (@ints) and:

  • if $int is positive, do nothing,
  • if $int is negative, reverse the sign of $result, or
  • if $int is zero, set $result = 0 and quit the loop.

This resolves all three of the issues listed above.

Try it 

Try running the script with any input:



example: 1, 2, 3, -1, -2, -3

Script


#!/usr/bin/perl

# Blog: http://ccgi.campbellsmiths.force9.co.uk/challenge

use v5.26;    # The Weekly Challenge - 2024-04-29
use utf8;     # Week 267 - task 1 - Product sign
use warnings; # Peter Campbell Smith
binmode STDOUT, ':utf8';

product_sign(-1, -2, -3, -4, 3, 2, 1);
product_sign(-1, -2, -3, 4, 3, 2, 1);
product_sign(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11);

sub product_sign {
    
    my (@ints, $product, $int, $result);
    
    @ints = @_;
    say qq[\nInput:   \@ints = (] . join(', ', @ints) . ')';
    
    # method 1 - simple
    $product = 1;
    $product *= $_ for @ints;
    say qq[Output1: ] . ($product ? $product / abs($product) : 0);
    
    # method 2 - more efficient
    $result = 1;
    for $int (@ints) {
        next if ($int > 0);     
        if ($int == 0) {
            $result = 0;
            last;
        }
        $result = -$result;
    }
    say qq[Output2: $result];
}

Output


Input:   @ints = (-1, -2, -3, -4, 3, 2, 1)
Output1: 1
Output2: 1

Input:   @ints = (-1, -2, -3, 4, 3, 2, 1)
Output1: -1
Output2: -1

Input:   @ints = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11)
Output1: 0
Output2: 0