14
\$\begingroup\$

Inspired by this challenge, and similar to this and this.

After seeing these, I figured I would continue the trend as there was no inclusive/exclusive sum. The goal here is to sum an interval of integers, either inclusive and exclusive, and output the total to stdout.

Input format: either a ( or [ followed by 2 comma separated integers followed by a ) or ]. Ex: [a, b] (a, b] [a, b) (a, b)

  • Note: b > a >= 0 and the range will always contain at least 1 value.
  • Input regex: [\(\[]\d+,\d+[\)\]]

Examples:

Input -> Output

[2,6] -> 20
(15,25] -> 205
[0,16) -> 120
(15,20) -> 70
[1,2) -> 1
(2,12] -> 75
[11,16] -> 81
(15,29) -> 286
[14,15) -> 14
(2,16] -> 133
(12,18) -> 75

This is code-golf, so the shortest code in bytes wins.

\$\endgroup\$
5
  • \$\begingroup\$ sandbox: codegolf.meta.stackexchange.com/questions/2140/… \$\endgroup\$
    – Underslash
    Apr 24, 2021 at 20:59
  • 2
    \$\begingroup\$ For what it's worth, I think this is closely related to the "Interpret Interval Notation" challenge (as my answer demonstrates), but as my vote alone would close this challenge, and I'm not entirely sold that they are duplicates, I'm not voting to close if/until other users think it's a duplicate. Otherwise, this is still an interesting challenge :) \$\endgroup\$ Apr 24, 2021 at 21:11
  • 5
    \$\begingroup\$ I think its similar, but because there are certain tricks involving sums (such as maybe using the fact that triangle numbers = sum(1, n)), the question is sufficiently different. \$\endgroup\$
    – Underslash
    Apr 24, 2021 at 21:15
  • 1
    \$\begingroup\$ If I was at my computer I'd dupe hammer this as solutions to the 3rd linked challenge can be trivially modified to output the sum instead of the product. \$\endgroup\$
    – Shaggy
    Apr 25, 2021 at 0:17
  • 1
    \$\begingroup\$ @Shaggy While solutions to that challenge may be changed into this, I think the fact that summing is considerably more variable leads to there being different solutions to that which could be shorter. In python for example, the sum() function is a built in, while prod() isn't. Similarly, there are different formulas for summing, whereas to my knowledge there aren't for multiplication. Just my thoughts on it though \$\endgroup\$
    – Underslash
    Apr 25, 2021 at 5:24

16 Answers 16

6
\$\begingroup\$

Jelly, 14 bytes

ḊṖVr/ḟ×ɗċⱮØ($S

A monadic Link accepting a list of characters that yields the sum of the described range.

Try it online! Or see the test-suite.

How?

ḊṖVr/ḟ×ɗċⱮØ($S - Link: list of characters, R  e.g. "[5,8)"
Ḋ              - dequeue                           "5,8)"
 Ṗ             - pop                               "5,8"
  V            - evaluate as Jelly                 [5,8]
                 (call that X)
            $  - last two links as a monad - f(R):
          Ø(   -   list of characters = "()"       "()"
         Ɱ     -   map across these with:
        ċ      -     count ocuurences (in R)       [0,1]
                     (call that Y)
       ɗ       - last three links as a dyad - f(X,Y):
    /          -   reduce (X) with:
   r           -     inclusive range               [5,6,7,8]
      ×        -   (X) multiply (Y) (vectorises)   [0,8]
     ḟ         -   filter discard                  [5,6,7]
             S - sum                               18
\$\endgroup\$
2
  • 2
    \$\begingroup\$ That r/ḟ×ɗ link with the brackets count on the right is brilliant! \$\endgroup\$ Apr 24, 2021 at 21:56
  • 1
    \$\begingroup\$ @cairdcoinheringaahing thanks it was, indeed, a satisfying discovery! \$\endgroup\$ Apr 24, 2021 at 22:01
5
\$\begingroup\$

Jelly, 16 bytes

ṙ1“(Ḋ)Ṗ,r”yḟØ[VS

Try it online!

Very similar to my answer to the related challenge

How it works

ṙ1“(Ḋ)Ṗ,r”yḟØ[VS - Main link. Takes a string S on the left
ṙ1               - Rotate the first character of S to the end
  “(Ḋ)Ṗ,r”       - String literal "(Ḋ)Ṗ,r"
          y      - Translate S according to this string
                    This splits the string into pairs of characters [["(", "Ḋ"], [")", "Ṗ"], [",", "r"]]
                    then for each pair, replaces all occurrences of the first character
                    with the second character e.g. ( -> Ḋ; ) -> Ṗ; , -> r
           ḟØ[   - Remove all square brackets
              V  - Evaluate as Jelly
               S - Sum

Why r, and ?

Consider the four possible examples with [, ], ( and ):

[2,6] -> 2,6][ -> 2r6
[2,6) -> 2,6)[ -> 2r6Ṗ
(2,6] -> 2,6]( -> 2r6Ḋ
(2,6) -> 2,6)( -> 2r6ṖḊ

The first step is rotating the string and the second step is translating and filtering.

r takes a number on the left and a number of the right and yields an inclusive range between them
takes a list and ops the last element off. rṖ is a right-exclusive range
takes a list and equeues it, removing the first element. rḊ is a left-exclusive range

Therefore, rṖḊ is a fully exclusive range

\$\endgroup\$
5
\$\begingroup\$

Python 3, 67 bytes

lambda s:sum(eval("range"+s.translate({91:"(",40:"(1+",93:"+1)"})))

Try it online!

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Hadn't heard of the translate function before - very cool solution! \$\endgroup\$
    – knosmos
    Apr 24, 2021 at 21:52
5
\$\begingroup\$

JavaScript (ES6),  66 ... 60  56 bytes

Saved 3 bytes by borrowing split(/\b/) from Redwolf Programs' answer

s=>([,x,c,y,p]=s.split(/\b/),(y-=p<c,x-=s>c)-y)*~(x+y)/2

Try it online!

How?

We extract the comma as c along with the other substrings so that it can be used to distinguish between parentheses and brackets.

The sum of the range \$[x..y]\$ is obtained with:

$$\frac{(y-x+1)(x+y)}{2}$$

implemented as:

((x - 1) - y) * ~((x - 1) + y) / 2

(Because x is a string, we do x -= s > c instead of x += s < c to force the coercion to a number at no cost. That's why \$x\$ is off by \$1\$ in the JS code.)

\$\endgroup\$
4
\$\begingroup\$

J, 30 bytes

1#.[:-.&i./']('&e.+3 1".&>@{;:

Try it online!

Explained using (2,12] as an example:

  • ;: Chop into words:

    ┌─┬─┬─┬──┬─┐
    │(│2│,│12│]│
    └─┴─┴─┴──┴─┘
    
  • 3 1".&>@{ Pluck the 3rd and 1st elements, and convert them to ints:

    12 2
    
  • ']('&e. Are ]( elements of the input? Returns boolean list:

    1 1
    
  • + Add the results of the previous 2 steps. This does the endpoint "adjustment" we'll need for the final step:

    13 3
    
  • [:-.&i./ Convert each of the above numbers to lists 0..<n-1>, and then set subtract. That is:

                                 v set minus
    0 1 2 3 4 5 6 7 8 9 10 11 12 -. 0 1 2
    3 4 5 6 7 8 9 10 11 12
    
  • 1#. Sum

    75
    
\$\endgroup\$
4
\$\begingroup\$

JavaScript (V8), 104 bytes

n=>[...Array(+(p=n.split(/\b/))[3]+(p[4]>"[")).keys(n=0)].filter(i=>i>=+p[1]+(p[0]<")")).map(i=>n+=i)&&n

Try it online!

\$\endgroup\$
3
\$\begingroup\$

Python 3, 105 88 bytes

def f(s):c,d=map(int,s[1:-1].split(','));return sum(range(c+(s[0]=="("),d+(s[-1]!=")")))

Ungolfed:

def sumOverRange(s):
    a = s[0]=="("
    b = s[-1]!=")"
    c, d = map(int, s[1:-1].split(','))
    return sum(range(c+a,d+b))
\$\endgroup\$
3
\$\begingroup\$

Add++, 40 bytes

L,BPBp","$t€v-1A:")"=0$_0A:"("=b[z£+¦rb+

Try it online!

Add++ ain't great at golfing, but it's surprisingly not awful here

How it works

L,		; Define a lambda that takes a string S
	BPBp	; Remove the first and last characters of S
	","$t	; Split on ","
	€v	; Evaluate each; Call this R
	-1A:	; Get the last character of S
	")"=	; Is it equal to ")"?
	0$_	; Negate
	0A:"("=	; Is the first character of S "("?
	b[	; Pair
	z£+	; Add to R
	¦r	; Range
	b+	; Sum
\$\endgroup\$
3
\$\begingroup\$

Python 3.6+, 57 bytes

lambda x:eval(f"sum(range({x<'['}+{x[1:-1]}+{']'in x}))")

An unnamed function accepting a string, x, that returns the sum of the range described.

Try it online!

How?

Evaluates code made with an f-string with the following three evaluated parts (as they are enclosed in {}s):

x<'[' - does x start with a character before ']'?
        ...effectively: does x start with a '('? -> True / False

x[1:-1] - x without its brackets

']'in x - does x contain a ']'?
          ...effectively: does x end with a ']' -> True / False

For example for x="(5,9)" the string will be:

sum(range(True+5,9+False))

In Python True and False are equivalent to 1 and 0 respectively, while the range(a,b) function is \$[a,b)\$ so range(True+5,9+False) is \$[1+5,9+0)=[6,9)\$ and evaluation sums this giving \$21\$.

\$\endgroup\$
3
\$\begingroup\$

Charcoal, 24 bytes

F⮌⪪S,⊞υ⁺Σι∨№ι(№ι]IΣ…⊟υ⊟υ

Try it online! Link is to verbose version of code. Explanation:

F⮌⪪S,

Split the input on , and loop over the parts (in reverse order, so that I can pop them off with one-byte instructions).

⊞υ⁺Σι∨№ι(№ι]

Extract the integer part from the string but increment it if the string contains a ( or a ]. This converts the range into the [..) form.

IΣ…⊟υ⊟υ

Create the range and take the sum.

\$\endgroup\$
2
\$\begingroup\$

Scala, 89 bytes

{case s"$a,$b"=>val(c,d)=a.tail.toInt->b.init.toInt;d*(d-1+b.last/42)-c*(c+1-a(0)/42)>>1}

Try it in Scastie!

Looks like math didn't win this time, although this answer is also long because parsing isn't too straightforward.

This uses the formula \$\frac{d(d-1+j)-c(c+1-i)}{2}\$, where \$c\$ is the first number, \$d\$ is the second number, \$i\$ is 2 if the start is closed and 0 otherwise, and \$j\$ is 2 if the end is closed and 0 otherwise.

Since the characters [ and ] are 91 and 93 in ASCII, respectively, when divided by 42, they become 2. The characters ( and ) are 40 and 41, so they become 0.

{case s"$a,$b" =>  //a is the part before the comma, b is the part after (including brackets)
val (c, d) = a.tail.toInt -> b.init.toInt; //c is the first number, d is the second
d*(d-1+b.last/42)  //d(d - 1 + j)
-c*(c+1-a(0)/42)   //- c(c + 1 - i)
>>1}               //divided by 2 (for operator precedence reasons)
\$\endgroup\$
2
\$\begingroup\$

Retina 0.8.2, 36 bytes

\d+
$*
[](]
1
M&!`(?<=(1*),1+)1*\1
1

Try it online! Link includes test cases. Explanation:

\d+
$*

Convert to unary.

[](]
1

Add 1 to ranges beginning ( or ending ], so that the range is now of the form [..).

M&!`(?<=(1*),1+)1*\1

List all of the integers in the range.

1

Sum them and convert to decimal.

\$\endgroup\$
2
\$\begingroup\$

Vyxal, s, 22 bytes

ḢṪ⌐:h⌊⁰h\(=+^t⌊⁰t\)=-ṡ

Try it Online!

I don't really know Vyxal so I suppose this can be golfed more. But the idea here is to get both the numbers and take sum of all integers between them. If the first character is (, then increase the first number by 1, and if the last character is ), then decrease the second number by 1.

ḢṪ⌐     # Remove first and last characters, then split by ","
:       # Duplicate
h⌊      # Take first element and convert to integer
⁰h\(=+  # Add 1 if the first character of input is equal to "("
^       # Reverse stack
t⌊      # Get last element and convert to integer
⁰t\)=-  # Subtract 1 if the last character of input is equal to ")"
ṡ       # Inclusive summation

\$\endgroup\$
2
\$\begingroup\$

C (gcc), 82 80 79 bytes

Saved 2 3 bytes thanks to ceilingcat!!!

a;b;c;f(char*s){sscanf(s+1,"%d,%d%c",&a,&b,&c);a-=*s&1;b-=c<42;b=a*~a-b*~b>>1;}

Try it online!

\$\endgroup\$
0
1
\$\begingroup\$

Haskell, 74 70 bytes

f(h:t)|(b,e)<-read$'(':init t++")"=sum$[b..e]++[-b|h<'[']++[-e|')'<-t]

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Perl 5, 72 bytes

/(\()?(\d+),(\d+)(\))?/;$m=$3-!!$4;$n=$2+!!$1;$_=($m*($m+1)-$n*($n-1))/2

Try it online!

Another beautiful regular expression saves the day. This regex has four capture groups.

  • $1 is truthy iff we start with an open parenthesis
  • $2 is the lower bound
  • $3 is the upper bound
  • $4 is truthy iff we end with a close parenthesis

From there, we set up our lower and upper bounds, using the conditional parentheses to adjust so we always have an inclusive range, and then it's just a matter of arithmetic.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.