Skip to content
loading...

re: Daily Coding Puzzles - Oct 29th - Nov 2nd VIEW POST

FULL DISCUSSION
 

Monday

Count of positives / sum of negatives (8 KYU):

Return an array, where the first element is the count of positives numbers and the second element is sum of negative numbers.

link

 
#! /usr/bin/perl
use warnings;
use strict;

use List::Util qw{ sum0 };

sub cpsn {
    return unless @_;
    my @neg = grep $_ <= 0, @_;
    return @_ - @neg, sum0(@neg)
}

use Test::More tests => 5;
is_deeply [cpsn()], [];
is_deeply [cpsn(-1)], [0, -1];
is_deeply [cpsn(0, 0)], [0, 0];
is_deeply [cpsn(2)], [1, 0];
is_deeply [cpsn(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, -11, -12, -13, -14, -15)],
          [10, -65];
 

Idk that this is an actual good Go solution - I'm not a Go expert so it can be hard for me to tell sometimes. It's so idiomatically verbose!

func Count(a []int) (r []int) {
    r = make([]int, 0)

    if len(a) == 0 {
        return
    }

    var pos int = 0
    var neg int = 0

    for _, item := range a {
        if item >= 0 {
            pos += 1
        } else {
            neg += item
        }
    }

    r = append(r, pos)
    return append(r, neg)
}
 
(defun monday (in-param)
    (list
        ;; positive numbers:
        (apply #'+ (remove-if-not #'plusp in-param))

        ;; negative numbers:
        (apply #'+ (remove-if #'plusp in-param))))

Usage:

* (monday (list 1 2 5 -2 -7))

(8 -9)
 
 

Solved it awhile ago (forgot about it).

Here is a C# answer.

using System.Linq;
using System;

public class Kata
{
    public static int[] CountPositivesSumNegatives(int[] a)
    {
        // guard clause for edge cases
        if (a == null || a.Length == 0) return new int[0];

        int count = 0;
        int sum = 0;
        // ".ToList()" is required to iterate the sequence
        a.Select(n => n > 0 ? count++ : sum += n).ToList();

        return new[] {count, sum};
    }
}

And just re-solved it using JavaScript

function countPositivesSumNegatives(input) {
    return (input && input.length >= 1) 
      ? input.reduce((acc, n) => {
          n > 0 ? acc[0]++ : acc[1] += n;
          return acc;
        }, [0, 0]) 
    : [];
}
 

The C# version is likely better solved with the linq aggregate monad. Less ram, no side effects.

Thanks for the suggestion there, @asparallel .

Here is the updated C# code (with the same logic as JavaScript one) using .Aggregate.

using System.Linq;
using System;

public class Kata
{
    public static int[] CountPositivesSumNegatives(int[] a)
    {
        return (a == null || a.Length == 0) 
          ? new int[0]
          : a.Aggregate(new [] {0, 0}, (acc, n) => {
              if (n > 0) acc[0]++;
              else acc[1] += n;
              return acc;
            });
    }
}

Further optimization I'd probably press for, use a tuple to move the entire aggregation onto the stack:

  public static IList<int> CountPositivesSumNegatives(int[] values)
  {
    if (values == null || values.Length == 0) return new int[0];

    var result = values.Aggregate((0, 0), (seed, value) =>
    {
      if (value > 0) seed.Item1++;
      else seed.Item2 += value;
      return seed;
    });

    return new[] { result.Item1, result.Item2 };
  }

Ah ha. Tuple being a value type, it is better optimized.
Thanks for the tips there 👊

 

Refactored to the code-golfiest thing ever with help of @joshcheek !

const countPositivesSumNegatives=i=>(i||[]).reduce(([c=0,s=0],v)=>v>0?[++c,s]:[c,s+v],[])
 

The golfiest version would probably be in Dyalog APL - even with newlines:

A←1 2 3 ¯4 ¯5 ¯6
X←+/(~A<0)/A
Y←+/(~A>0)/A
O←X Y

Output:

    O
6 ¯15

I will one day be able to look at APL without my brain leaking out of my ears.

Today is not that day.

This was my first time trying to actually do something with it. It was fun and it still sucked my brains out. (Both of them.)

Oh holy shit! I was looking at it for several minutes and it started making sense! Maybe because I thought through problem with @aspittel , or maybe this APL is more sensible (the last one I saw, someone had spilled a bag of unicode across its source).

I'm using Ruby's comment syntax because IDK how to do it in APL

# Haskell uses arrows for assignment in `do` blocks.
# Whitespace delimited numbers are a thing in lisp.
# The high bar looks a lot like a minus sign, so:

A←                 # set into the variable A
A←1 2 3 ¯4 ¯5 ¯6   # the list of numbers: [1, 2, 3, -4, -5, -6]


# Haskell iplements + as a function that you can pass around
# The slash looks like and is used like a shell pipeline.
# Tilde is logical negation in many syntaxes.
# `A` in `A<0` is like SQL, which uses the
# table name to refer to that table's current row.

X←             # set into the variable X
X←+/           # the sum of
X←+/(~         # the numbers which aren't
X←+/(~A<0)/    # negative
X←+/(~A<0)/A   # from the list A

Y←            # set into the variable Y
Y←+/          # the sum of
Y←+/(~        # the variables that aren't
Y←+/(~A>0)/   # positive
Y←+/(~A>0)/A  # from the list A

O←X Y    # set X and Y as the output

maybe this APL is more sensible (the last one I saw, someone had spilled a bag of unicode across its source).

That's the thing with first tries: You mostly write code which is relatively easy to understand. The APL symbol for comments is , by the way. And I have no idea how to write it without a Unicode table. ;-)

Thank you for your explanation. I finally understand wtf I was doing. (I know that I could probably have obfuscated it even more, "not negative" is longer than "positive", but I think I still won.)

 

Q/kdb+ solution (let l be the input list):

(sum l > 0; sum l where l < 0)
 

F#

let update (count, sum) value =
    if value > 0 then (count + 1), sum
    else              count, (sum + value)

// usage, start with 0 count/sum, update them for each value
let (count, sum) = Array.fold update (0, 0) inputArr

This returns a tuple instead of an array, which I believe is an improvement.

 

Python 3 solution update. Posted to the wrong part of the discussion :P


def count_and_sum(arr, x):
    if not arr == None and len(arr) > 0:
        ct = len([i for i in arr if i > x])
        sum_neg = sum([i for i in arr if i <= x])
        return [ct, sum_neg]
    else:
        return([])
 

Haskell

countPositivesSumNegatives :: [Int] -> [Int]
countPositivesSumNegatives input =
    let positives = length $ filter (>= 0) input in
    let negatives = sum $ filter (<0) input in
    [positives, negatives]
 

TypeScript

export function countPositivesSumNegatives(input: number[]) : number[] {
  let positiveCount = 0, negativeSum = 0;
  if(!input || !input.length) return [];
  for(let num of input) {
      if(num <= 0) negativeSum += num;
      else positiveCount++;
    }
  return [positiveCount, negativeSum];
}
code of conduct - report abuse