# Product over exclusive and inclusive ranges

Inspired by this question by @CᴏɴᴏʀO'Bʀɪᴇɴ.

Taken from the question:

Your task is simple: given two integers a and b, output ∏[a,b]; that is, the product of the range between a and b. You may take a and b in any reasonable format, whether that be arguments to a function, a list input, STDIN, et cetera. You may output in any reasonable format, such as a return value (for functions) or STDOUT. a will always be less than b.

Note that the end may be exclusive or inclusive of b. I'm not picky. ^_^

The difference for this challenge is we are going to be picky about the range type. Input is a string of the form [a,b], (a,b], [a,b), or (a,b) where a [] is an inclusive boundary and () is an exclusive boundary. Given the explicit boundaries, provide the product of the range. Also the input range will always include at least 1 number, meaning ranges like (3,4) are invalid and need not be tested.

## Test cases

[a,b) => result
[2,5) => 24
[5,10) => 15120
[-4,3) => 0
[0,3) => 0
[-4,0) => 24

[a,b] => result
[2,5] => 120
[5,10] => 151200
[-4,3] => 0
[0,3] => 0
[-4,-1] => 24

(a,b] => result
(2,5] => 60
(5,10] => 30240
(-4,3] => 0
(0,3] => 6
(-4,-1] => -6

(a,b) => result
(2,5) => 12
(5,10) => 3024
(-4,3) => 0
(0,3) => 2
(-4,0) => -6


This is a , so the shortest program in bytes wins.

The Stack Snippet at the bottom of this post generates the catalog from the answers a) as a list of shortest solution per language and b) as an overall leaderboard.

## Language Name, N bytes


where N is the size of your submission. If you improve your score, you can keep old scores in the headline, by striking them through. For instance:

## Ruby, <s>104</s> <s>101</s> 96 bytes


If there you want to include multiple numbers in your header (e.g. because your score is the sum of two files or you want to list interpreter flag penalties separately), make sure that the actual score is the last number in the header:

## Perl, 43 + 2 (-p flag) = 45 bytes


You can also make the language name a link which will then show up in the snippet:

## [><>](http://esolangs.org/wiki/Fish), 121 bytes


var QUESTION_ID=66285,OVERRIDE_USER=44713;function answersUrl(e){return"https://api.stackexchange.com/2.2/questions/"+QUESTION_ID+"/answers?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+ANSWER_FILTER}function commentUrl(e,s){return"https://api.stackexchange.com/2.2/answers/"+s.join(";")+"/comments?page="+e+"&pagesize=100&order=desc&sort=creation&site=codegolf&filter="+COMMENT_FILTER}function getAnswers(){jQuery.ajax({url:answersUrl(answer_page++),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){answers.push.apply(answers,e.items),answers_hash=[],answer_ids=[],e.items.forEach(function(e){e.comments=[];var s=+e.share_link.match(/\d+/);answer_ids.push(s),answers_hash[s]=e}),e.has_more||(more_answers=!1),comment_page=1,getComments()}})}function getComments(){jQuery.ajax({url:commentUrl(comment_page++,answer_ids),method:"get",dataType:"jsonp",crossDomain:!0,success:function(e){e.items.forEach(function(e){e.owner.user_id===OVERRIDE_USER&&answers_hash[e.post_id].comments.push(e)}),e.has_more?getComments():more_answers?getAnswers():process()}})}function getAuthorName(e){return e.owner.display_name}function process(){var e=[];answers.forEach(function(s){var r=s.body;s.comments.forEach(function(e){OVERRIDE_REG.test(e.body)&&(r="<h1>"+e.body.replace(OVERRIDE_REG,"")+"</h1>")});var a=r.match(SCORE_REG);a&&e.push({user:getAuthorName(s),size:+a[2],language:a[1],link:s.share_link})}),e.sort(function(e,s){var r=e.size,a=s.size;return r-a});var s={},r=1,a=null,n=1;e.forEach(function(e){e.size!=a&&(n=r),a=e.size,++r;var t=jQuery("#answer-template").html();t=t.replace("{{PLACE}}",n+".").replace("{{NAME}}",e.user).replace("{{LANGUAGE}}",e.language).replace("{{SIZE}}",e.size).replace("{{LINK}}",e.link),t=jQuery(t),jQuery("#answers").append(t);var o=e.language;/<a/.test(o)&&(o=jQuery(o).text()),s[o]=s[o]||{lang:e.language,user:e.user,size:e.size,link:e.link}});var t=[];for(var o in s)s.hasOwnProperty(o)&&t.push(s[o]);t.sort(function(e,s){return e.lang>s.lang?1:e.lang<s.lang?-1:0});for(var c=0;c<t.length;++c){var i=jQuery("#language-template").html(),o=t[c];i=i.replace("{{LANGUAGE}}",o.lang).replace("{{NAME}}",o.user).replace("{{SIZE}}",o.size).replace("{{LINK}}",o.link),i=jQuery(i),jQuery("#languages").append(i)}}var ANSWER_FILTER="!t)IWYnsLAZle2tQ3KqrVveCRJfxcRLe",COMMENT_FILTER="!)Q2B_A2kjfAiU78X(md6BoYk",answers=[],answers_hash,answer_ids,answer_page=1,more_answers=!0,comment_page;getAnswers();var SCORE_REG=/<h\d>\s*([^\n,]*[^\s,]),.*?(\d+)(?=[^\n\d<>]*(?:<(?:s>[^\n<>]*<\/s>|[^\n<>]+>)[^\n\d<>]*)*<\/h\d>)/,OVERRIDE_REG=/^Override\s*header:\s*/i;
body{text-align:left!important}#answer-list,#language-list{padding:10px;width:290px;float:left}table thead{font-weight:700}table td{padding:5px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="//cdn.sstatic.net/codegolf/all.css?v=83c949450c8b"> <div id="answer-list"> <h2>Leaderboard</h2> <table class="answer-list"> <thead> <tr><td></td><td>Author</td><td>Language</td><td>Size</td></tr></thead> <tbody id="answers"> </tbody> </table> </div><div id="language-list"> <h2>Winners by Language</h2> <table class="language-list"> <thead> <tr><td>Language</td><td>User</td><td>Score</td></tr></thead> <tbody id="languages"> </tbody> </table> </div><table style="display: none"> <tbody id="answer-template"> <tr><td>{{PLACE}}</td><td>{{NAME}}</td><td>{{LANGUAGE}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table> <table style="display: none"> <tbody id="language-template"> <tr><td>{{LANGUAGE}}</td><td>{{NAME}}</td><td>{{SIZE}}</td><td><a href="{{LINK}}">Link</a></td></tr></tbody> </table>

# LabVIEW, 38 LabVIEW Primitives

"slightly" modified, now sets the ranges by scanning for () and [] and adding the index to the numbers.

• By having a language that requires a fancy gif, you have immediately gained ∞ rep. GG. +1 – Addison Crump Dec 11 '15 at 12:38

## Python 2, 72 bytes

lambda s:reduce(int.__mul__,range(*eval(s[1:-1]+'+'+']'in s))[s<'[':])


To extract the numbers we evaluate s[1:-1], the input string with ends removed, which gives a tuple. The idea is to get the range of this tuple and take the product.

lambda s:reduce(int.__mul__,range(*eval(s[1:-1]))


The fudging happens to adjust the endpoints. The upper endpoint is easy, just cut off the first element if the input starts with (, done as [s<'[':].

The other endpoint is trickier. Python doesn't have a clean way to conditionally remove the last element of a list because l[:0] removes the whole thing. So, we do something weird. We modify the tuple string before it is evaluated to tack on the string "+True" or "+False" depending on whether s ends in ] or ). The result is that something like 3,7 becomes either 3,7+False which is 3,7, or 3,7+True which is 3,8.

Alternate, prettier 72:

lambda s:eval("reduce(int.__mul__,range((s<'[')+%s+(']'in s)))"%s[1:-1])


## Minecraft 15w35a+, program size 638 total (see below)

Same as my answer here, but modified. Since Minecraft has no string input, I took the liberty of keeping scoreboard input. If that is a problem, consider this answer non-competitive.

This calculates PI a,b with inclusive / exclusive specified by the two levers. Input is given by using these two commands: /scoreboard players set A A {num} and /scoreboard players set B A {num}. Remember to use /scoreboard objectives add A dummy before input.

Scored using: {program size} + ( 2 * {input command} ) + {scoreboard command} = 538 + ( 2 * 33 ) + 34 = 638.

This code corresponds to the following psuedocode:

R = 1
T = A
loop:
R *= A
A += 1
if A == B:
if A.exclusive:
R /= T
if B.exclusive:
R /= B
print R
end program


# Pyth, 20 bytes

*FPW}\)ztW}$$z}FvtPz  Try it online: Demonstration or Test Suite ### Explanation: *FPW}$$ztW}$$z}FvtPz implicit: z = input string tPz remove the first and last character of z v evaluate, returns a tuple of numbers }F inclusive range tW remove the first number, if }\(z "(" in z PW remove the last number, if }$$z                  ")" in z
*F                     compute the product of the remaining numbers


# Ruby, 79 77 bytes

->s{a,b=s.scan /\-?\d+/;(a.to_i+(s[?[]?0:1)..b.to_i-(s[?]]?0:1)).reduce 1,:*}


79 bytes

->s{a,b=s.scan(/\-?\d+/).map &:to_i;((s[?[]?a:a+1)..(s[?]]?b:b-1)).reduce 1,:*}


Ungolfed:

-> s {
a,b=s.scan /\-?\d+/    # Extracts integers from the input string, s
(
a.to_i+(s[?[]?0:1).. # Increase start of the range by 1 if s contains (
b.to_i-(s[?]]?0:1)   # Decrease end of the range by 1 if s contains )
).reduce 1,:*
}


Usage:

->s{a,b=s.scan /\-?\d+/;(a.to_i+(s[?[]?0:1)..b.to_i-(s[?]]?0:1)).reduce 1,:*}["(2,5]"]
=> 60


## Seriously, 31 bytes

,#d@p@',@sεj≈Mi(@)']=+)'(=+xπ


Takes input as a string (wrapped in double quotes)

Try it online (input must be manually entered)

Explanation:

,#d@p@                             get input, take first and last character off and push them individually
',@sεj≈Mi                  split on commas, map: join on empty, cast to int; explode list
(@)']=+)'(=+      increment start and end if braces are ( and ] respectively (since range does [a,b))
xπ    make range, push product


# Python 3, 104

y,r=input().split(',')
t=int(y[1:])+(y[0]<')')
for x in range(t+1,int(r[:-1])+(r[-1]>'[')):t*=x
print(t)


Takes input from stdin.

• we actually posted our answers in the same second O.o – Eumel Dec 10 '15 at 15:40
• @Eumel That should be a badge. – Morgan Thrapp Dec 10 '15 at 15:41
• ill actually post that on Meta right now^^ – Eumel Dec 10 '15 at 15:42
• @Eumel: Actually you posted yours 1 second before Morgan Thrapp's – ev3commander Dec 11 '15 at 2:11
• oh really? it showed answered n seconds ago on both answers – Eumel Dec 11 '15 at 8:47

# MATLAB, 86 70 bytes

s=sscanf(input(''),'%c%d,%d%c');a=s<42;disp(prod(a(1)+s(2):s(3)-a(4)))


This also works with Octave. You can try online here. I have added the code as a script to that workspace, so you can just enter productRange at the prompt, then enter your input, e.g. '(2,5]'.

So the code first scans the input to extract the brackets and the numbers together:

s=sscanf(input(''),'%c%d,%d%c');


This returns an array which is made of [bracket, number, number, bracket].

The array is compared with 42, actually any number between 42 and 90 inclusive will do. This determines which sort of bracket it was, giving a 1 if it is an exclusive bracket, and a 0 if an inclusive bracket.

a=s<42;


Finally, we display the product of the required range:

disp(prod(a(1)+s(2):s(3)-a(4)))


The product is of numbers staring with the first number s(2) plus the first bracket type a(1) (which is a 1 if an exclusive bracket), ranging up to and including the second number s(3) minus the second bracket type a(4). This gives the correct inclusive/exclusive range.

# Julia, 75 bytes

s->prod((x=map(parse,split(s[2:end-1],",")))[1]+(s[1]<41):x[2]-(s[end]<42))


This is an anonymous function that accepts a string and returns an integer. To call it, give it a name, e.g. f=s->....

Ungolfed:

function f(s::AbstractString)
# Extract the numbers in the input
x = map(parse, split(s[2:end-1], ","))

# Construct a range, incrementing or decrementing the endpoints
# based on the ASCII value of the surrounding bracket
r = x[1]+(s[1] == 40):x[2]-(s[end] == 41)

# Return the product over the range
return prod(r)
end


## Mathematica, 128 bytes

1##&@@Range[(t=ToExpression)[""<>Rest@#]+Boole[#[[1]]=="("],t[""<>Most@#2]-Boole[Last@#2==")"]]&@@Characters/@#~StringSplit~","&


This is too long... Currently thinking about a StringReplace + RegularExpression solution.

# PowerShell, 146 104 Bytes

param($i)$a,$b=$i.trim("[]()")-split',';($a,(1+$a))[$i[0]-eq'(']..($b,(+$b-1))[$i[-1]-eq')']-join'*'|iex


Golfed off 42 bytes by changing how the numbers are extracted from the input. Woo!

param($i) # Takes input string as$i
$a,$b=$i.trim("[]()")-split',' # Trims the []() off$i, splits on comma,
# stores the left in $a and the right in$b

($a,(1+$a))[$i[0]-eq'(']..($b,(+$b-1))[$i[-1]-eq')']-join'*'|iex
# Index into a dynamic array of either $a or$a+1 depending upon if the first
# character of our input string is a ( or not
# .. ranges that together with
# The same thing applied to $b, depending if the last character is ) or not # Then that's joined with asterisks before # Being executed (i.e., eval'd)  # Japt, 43 41 bytes [VW]=Uf"\\d+";ÂV+Â('A>Ug¹oÂW+Â('A<UtJ¹r*1  Try it online! # Perl 6, 60 bytes {s/$$(\-?\d+)/[0^/;s/(\-?\d+)$$/^$0]/;s/\,/../;[*] EVAL $_}  There is a bit of mis-match because the way you would write the (2,5] example in Perl 6 would be 2^..5 ([2^..5] also works). So I have to swap (2 with [2^, and , with .., then I have to EVAL it into a Range. usage: # give it a name my &code = {...} # the $ = is so that it gets a scalar instead of a constant

say code $= '(2,5)'; # 12 say code$ = '[2,5)'; # 24
say code $= '(2,5]'; # 60 say code$ = '[2,5]'; # 120

say code $= '(-4,0)' # -6 say code$ = '[-4,0)' # 24
say code $= '(-4,0]' # 0 say code$ = '[-4,0]' # 0

say code $= '(-4,-1)' # 6 say code$ = '[-4,-1)' # -24
say code $= '(-4,-1]' # -6 say code$ = '[-4,-1]' # 24

# this is perfectly cromulent,
# as it returns the identity of *
say code $= '(3,4)'; # 1  # CJam, 34 bytes r)$$@+"[()]"2/\.#\',/:i.+~1-,f+:*  Try it online Explanation: r Read input. ) Split off last character. \ Swap rest of input to top. ( Split off first character. @ Rotate last character to top. + Concatenate first and last character, which are the two braces. "[()]" Push string with all possible braces. 2/ Split it into start and end braces. \ Swap braces from input to top. .# Apply find operator to vector elements, getting the position of each brace from input in corresponding list of possible braces. The lists of braces are ordered so that the position of each can be used as an offset for the start/end value of the interval. \ Swap remaining input, which is a string with two numbers separated by a comma, to top. ',/ Split it at comma. :i Convert the two values from string to integer. .+ Element-wise addition to add the offsets based on the brace types. ~ Unwrap the final start/end values for the interval. 1 Copy start value to top. - Subtract it from end value. , Build 0-based list of values with correct length. f+ Add the start value to all values. :* Reduce with multiplication.  # JavaScript (ES6), 90 bytes s=>eval(for(n=s.match(/-*\\d+/g),i=n[0],c=s[0]<"["||i;++i<+n[1]+(s.slice(-1)>")");)c*=i)  ## Explanation s=> eval( // use eval to allow for loop without return or {} for( n=s.match(/-*\\d+/g), // n = array of input numbers [ a, b ] i=n[0], // i = current number to multiply the result by c=s[0]<"["||i; // c = result, initialise to a if inclusive else 1 ++i<+n[1] // iterate from a to b +(s.slice(-1)>")"); // if the end is inclusive, increment 1 more time ) c*=i // multiply result ) // implicit: return c  ## Test var solution = s=>eval(for(n=s.match(/-*\\d+/g),i=n[0],c=s[0]<"["||i;++i<+n[1]+(s.slice(-1)>")");)c*=i) <input type="text" id="input" value="(5,10]" /> <button onclick="result.textContent=solution(input.value)">Go</button> <pre id="result"></pre> # R, 102 104 bytes f=function(s){x=scan(t=gsub('\\(|\$|,|\$$|\$',' ',s))+c(grepl('^\$$',s),-(grepl('\$$$',s)));prod(x[1]:x[2])}


Ungolfed

f=function(s){
# remove delimiting punctuation from input string, parse and return an atomic vector
x=scan(t=gsub('\$$|\$|,|\$$|\$',' ',s)) +
# add /subtract from the range dependent on the [) pre/suf-fixes
c(grepl('^\$$',s),-(grepl('\$$$',s))) # get the product of the appropriate range of numbers prod(x[1]:x[2]) }  edit to allow negative numbers [at the expense of 2 more characters • Language?​​​​​​ – ThisSuitIsBlackNot Dec 11 '15 at 3:38 • @ThisSuitIsBlackNot --R (and fixed in answer) – mnel Dec 11 '15 at 4:22 # JavaScript (ES6), 79 As an anonymous method r=>eval("[a,b,e]=r.match(/-?\\d+|.$/g);c=a-=-(r<'@');for(b-=e<'@';a++<b;)c*=a")


Test snippet

F=r=>eval("[a,b,e]=r.match(/-?\\d+|.\$/g);c=a-=-(r<'@');for(b-=e<'@';a++<b;)c*=a")

// TEST
console.log=x=>O.innerHTML+=x+'\n'

;[
['[2,5)',24],['[5,10)',15120],['[-4,3)',0],['[0,3)',0],['[-4,0)',24],
['[2,5]',120],['[5,10]',151200],['[-4,3]',0],['[0,3]',0],['[-4,-1]',24],
['(2,5]',60],['(5,10]',30240],['(-4,3]',0],['(0,3]',6],['(-4,-1]',-6],
['(2,5)',12],['(5,10)',3024],['(-4,3)',0],['(0,3)',2],['(-4,0)',-6]
].forEach(t=>{
r=F(t[0]),k=t[1],console.log(t[0]+' -> '+r+' (check '+k+ (k==r?' ok)':' fail)'))
})
<pre id=O></pre>