34
\$\begingroup\$

Based on this question from Code Review.

Given precisely three positive integers, return the product of all of the distinct inputs. If none of the inputs are distinct, return 1. That is, implement the function:

\$ f(a,b,c) = \cases{1 & $a = b = c $ \\ a & $ b = c $ \\ b & $ a = c $ \\ c & $ a = b $ \\ a b c & otherwise } \$

Shortest code in each language wins.

Test cases

a, b, c -> f(a,b,c)
7, 7, 7 -> 1
3, 3, 5 -> 5
2, 6, 6 -> 2
3, 4, 3 -> 4
1, 2, 3 -> 6
12, 9, 16 -> 1728
\$\endgroup\$
  • 1
    \$\begingroup\$ "(a=b)∩(b=c)" - did you mean \wedge instead of \cap? \$\endgroup\$ – ngn Feb 11 at 6:54
  • 12
    \$\begingroup\$ I’m pretty sure simply writing a = b = c is more readable. \$\endgroup\$ – Fatalize Feb 11 at 8:42
  • \$\begingroup\$ I wrote it the way I did thinking it would be clearer to an average reader of this site, but really I was probably overthinking it. I've changed it now, thanks for the suggestions! \$\endgroup\$ – FryAmTheEggman Feb 11 at 16:18
  • \$\begingroup\$ @ngn I like \land. same effect, more meaningful (stupid \cap and \cup) \$\endgroup\$ – qwr Feb 12 at 3:33

37 Answers 37

11
\$\begingroup\$

C (gcc), 46 \$\cdots\$ 43 42 bytes

Saved 2 bytes thanks to 79037662!!!

f(a,b,c){a=a^b?a^c?b^c?a*b*c:a:b:b^c?c:1;}

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ I believe you can use a^c (bitwise xor) to check for equality which is shorter than c==a. Note that you'd have to flip the other parts of the ternary. \$\endgroup\$ – 79037662 Feb 10 at 19:04
  • \$\begingroup\$ @79037662 Yes, I have thought of that but my head's still spinning from getting this to work! T_T \$\endgroup\$ – Noodle9 Feb 10 at 19:20
  • \$\begingroup\$ Here's a version for 45 bytes, I think it can be reduced further but I'm not sure. tio.run/##S9ZNT07@/… \$\endgroup\$ – 79037662 Feb 10 at 19:37
  • 1
    \$\begingroup\$ @79037662 Well done - we got there! :-) \$\endgroup\$ – Noodle9 Feb 10 at 19:52
  • 1
    \$\begingroup\$ @AdamChalcraft gcc uses the same register for the first function parameter and the return value if they're both int. So yes, it's a golf hack to simply assign the return value to the first parameter. \$\endgroup\$ – Noodle9 Feb 11 at 9:51
10
\$\begingroup\$

05AB1E, 3 bytes

¢ÏP

Try it online!

¢       # count occurences of each number
 Ï      # keep only those where the count is 1
  P     # product (1 if the list is empty)
\$\endgroup\$
  • \$\begingroup\$ I had this exact solution prepared when I saw it in the Sandbox last week. Of course it had to go live yesterday evening, haha. ;) Obvious +1 from me. \$\endgroup\$ – Kevin Cruijssen Feb 11 at 7:26
9
\$\begingroup\$

JavaScript (ES6), 38 bytes

(a,b,c)=>a-b?b-c?c-a?a*b*c:b:a:b-c?c:1

Try it online!


JavaScript (ES6), 53 bytes

Takes input as [a,b,c].

A=>[[a,b,c]=A,1,a-b?a-c?a:b:c,a*b*c][new Set(A).size]

Try it online!

Commented

A =>                // A[] = input
  [                 // lookup table:
    [a, b, c] = A,  //   set size = 0 --> impossible, so use this slot
                    //   to split A[] into 3 distinct variables
    1,              //   set size = 1 --> return 1
    a - b ?         //   set size = 2 --> if a is not equal to b:
      a - c ?       //     if a is not equal to c:
        a           //       return a
      :             //     else:
        b           //       return b
    :               //   else:
      c,            //     return c
    a * b * c       //   set size = 3 --> return a * b * c
  ]                 //
  [new Set(A).size] // index into lookup table = size of the set
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks for including the second solution. It's way cooler than the fully golfed version. \$\endgroup\$ – begolf123 Feb 10 at 19:32
  • \$\begingroup\$ For the case where two are the same, a^b^c gives the unique one. That saves 8 bytes in the second version. \$\endgroup\$ – kaya3 Feb 11 at 5:48
6
\$\begingroup\$

J, 10 bytes

*/@-.}./.~

Try it online!

     }./.~  group by value and remove one from each group
   -.       set subtract from input
*/          product
\$\endgroup\$
  • \$\begingroup\$ This is quite nice \$\endgroup\$ – Jonah Feb 11 at 0:54
6
\$\begingroup\$

APL (Dyalog), 10 bytes

Thanks to Adám and Bubbler in chat for helping golf this

×/∪*1=⊢∘≢⌸

Try it online!

Explanation:

×/             ⍝ Reduce by multiplication
  ∪            ⍝ The unique values of the input
   *           ⍝ To the power of
    1=         ⍝ Whether one is equal to
        ≢      ⍝ The length of
      ⊢∘ ⌸     ⍝ The indexes of each unique element
\$\endgroup\$
6
\$\begingroup\$

R, 40 37 bytes

-3 bytes by taking input with scan().

prod(unique(x<-scan())^2,1/x)^!!sd(x)

Try it online!

sd(x) computes the standard deviation (which is 0 iff all entries are equal), so !!sd(x) is TRUE if some entries are different, and FALSE if all are equal.

  • if all entries are different, then unique(x)==x, so we are down to prod(x)^1
  • if 2 entries are equal, then the corresponding value gets cancelled out between unique(x)^2 and 1/x, so we are left with the sole "lonely" value
  • if all 3 entries are equal, then we have (...)^0 which is 1.

This is shorter than anything I could come up with based on table, tabulate, duplicated or rle(sort()).

\$\endgroup\$
  • 1
    \$\begingroup\$ I had the obvious 47 bytes with duplicated; I did not even come close to this approach! \$\endgroup\$ – Giuseppe Feb 10 at 23:35
  • \$\begingroup\$ I think I've pipped you to 39 with rle(sort()), don't have the chance to fully bugtest it right now though. Apparently prod(numeric(0)) == 1 so it might be solid: Try it online! \$\endgroup\$ – CriminallyVulgar Feb 11 at 14:31
  • \$\begingroup\$ @CriminallyVulgar The main reason for the difference is that you are using scan() to take input (which is surely fine). With scan(), my solution goes down to 37 bytes: Try it online! \$\endgroup\$ – Robin Ryder Feb 11 at 14:55
  • 1
    \$\begingroup\$ @RobinRyder I was massively overcomplicating my indexing at the ends, so here's 36: Try it online! \$\endgroup\$ – CriminallyVulgar Feb 11 at 15:38
  • 1
    \$\begingroup\$ @CriminallyVulgar Well done! Worth posting separately IMO. \$\endgroup\$ – Robin Ryder Feb 11 at 16:28
5
\$\begingroup\$

Python, 48 bytes

lambda l:eval("(%sin[%s,%s]or %s)*"*3%(l*4)+"1")

Try it online!

Takes in a tuple. The idea is similar to an answer in the Code Review question, which can be golfed to:

51 bytes

lambda a,b,c:a**(b!=a!=c)*b**(c!=b!=a)*c**(a!=c!=b)

Try it online!

Each element is included in the product if it's different from the other two, with the power setting to a harmless x**0 == 1 otherwise. We want to avoid writing the three similar terms being multiplied. Python unfortunately doesn't have a built-in list product without imports. So, we turn to eval shenanigans.

We use a longer expression that use logical short-circuiting:

60 bytes

lambda a,b,c:(a in[b,c]or a)*(b in[c,a]or b)*(c in[a,b]or c)

Try it online!

In this expression, the variable names cycle through a,b,c in that order four times. So, by tripling the format string "(%sin[%s,%s]or %s)*" and plugging in the input tuple repeated four times, we get the desired expression. We just need to append a "1" to deal with the trailing multiplication.

\$\endgroup\$
  • \$\begingroup\$ Very nice! I only found the 51 :) \$\endgroup\$ – FryAmTheEggman Feb 11 at 5:30
  • \$\begingroup\$ @FryAmTheEggman so this was it! I had the expression with the powers but I wasn't being able to write it in a short format! \$\endgroup\$ – RGS Feb 11 at 8:49
4
\$\begingroup\$

Haskell, 37 bytes

f l=product[x|x<-l,filter(==x)l==[x]]

Try it online!

Pretty straightforward -- filter for elements that appear only once and take the product.

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

Excel (Version 1911), 80 Bytes, 42 Bytes

=PRODUCT(FILTER(A1#,COUNTIF(A1#,A1#)=1,1))

Input entered as a static column array (e.g. ={1;2;3}) in cell A1

  • Saved 38 bytes due to inspiration from Grimmy's 05AB1E solution.
\$\endgroup\$
4
\$\begingroup\$

PHP, 72 71 bytes

sort($argv);[,$a,$b,$c]=$argv;echo$a-$b?$b-$c?$a*$b*$c:$a:($b-$c?$c:1);

Try it online!

Might be shorter without the sort but nested ternary operator precedence blows my mind.

-1 byte thanks to @640KB

PHP, 66 bytes

fn($a,$b,$c)=>$a-$c?$a-$b?$b-$c?$a*$b*$c:$a:$b==$c?:$c:$b==$c?:$b;

Try it online!

Kudos to @640KB for taming the ternary operator beast!

\$\endgroup\$
  • \$\begingroup\$ Think you can -1 byte removing the $n= tio.run/##LcixCoAgEAbgl/kHDR2CXLTwQaLh7ojcFIte/… \$\endgroup\$ – 640KB Feb 13 at 16:44
  • \$\begingroup\$ And here's a ternary version without the sort()! tio.run/##Vc9Ba4MwFAfw8/Ip/… \$\endgroup\$ – 640KB Feb 13 at 17:11
  • \$\begingroup\$ I think the $b==$c can be reduced down to $b-$c by inverting the ternary truth/false parts. Not sure if my brain can handle it. \$\endgroup\$ – Guillermo Phillips Feb 13 at 17:17
  • \$\begingroup\$ What happens with subtraction is that it changes the order of operations of the chained ternaries and you'd have to put parenthesis around it, so it actually adds one byte. \$\endgroup\$ – 640KB Feb 13 at 17:19
  • \$\begingroup\$ Gotcha! Thanks. \$\endgroup\$ – Guillermo Phillips Feb 13 at 17:20
3
\$\begingroup\$

GolfScript, 31 bytes

...{{*}*}:m;m\.|m/-m\.|,1=\1\if

This was... a lot more difficult than I thought it would be. Can be optimized. So much so, that I don't really want to give this much of an explanation.

Here's the process:

Take your input array and make 3 more copies of it. Make a function m, which multiplies the elements in an array together. Do that to the first array, then eliminate dupes from a second (keeping one of each). Perform m on it, then divide it from the first number. You should have the duplicate number (if there's only one pair dupe). Remove it rom your array, then return the last number. If the "suspected dupe" is 1, then just multiply again and output. If, when you remove all of the "suspected dupe"s, you're left with an array of size 1, just output 1 instead.

This was incredibly and probably needlessly complicated, but I couldn't find any good GolfScript shortcuts besides the multiplication bit. PITA.

Try it online, I guess

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

PowerShell, 44 bytes

,1+($args|group|? C* -eq 1|% N*)-join'*'|iex

Try it online!

where |? C* -eq 1 means |? Count -eq 1 and |% N* means |% Name.


PowerShell, 45 bytes

$p=1;$args|group|? C* -eq 1|%{$p*=$_.Name};$p

Try it online!

\$\endgroup\$
  • 1
    \$\begingroup\$ Ah, that's really clever. I was playing around with something similar, but couldn't get it functional. \$\endgroup\$ – AdmBorkBork Feb 10 at 20:28
3
\$\begingroup\$

Jelly,  7  6 bytes

ḟœ-Q$P

Try it online!

How?

ḟœ-Q$P - list, L
    $  - last two links as a monad:
   Q   -   de-duplicate (L)
 œ-    -   (L) multi-set difference (that)
ḟ      - (L) filter discard if in (that)
     P - product

7s:

ĠṖÐḟị⁸P
ḟṖƙ`F$P
\$\endgroup\$
  • \$\begingroup\$ @FryAmTheEggman was it that? \$\endgroup\$ – Jonathan Allan Feb 10 at 21:11
  • 1
    \$\begingroup\$ Basically, just reordered: œ-QɓḟP \$\endgroup\$ – FryAmTheEggman Feb 10 at 21:21
3
\$\begingroup\$

Wolfram Language (Mathematica), 31 bytes

#&@@Times@@Tally@#~Cases~{_,1}&

Try it online!

\$\endgroup\$
  • \$\begingroup\$ #&@@ and {a_,1}->a use the same number of characters to take first but the rule has lower precedence than the infix operator. \$\endgroup\$ – Hood Feb 11 at 3:58
3
\$\begingroup\$

R, 36 bytes

prod((a=rle(sort(scan())))$v[a$l<2])

Try it online!

rle() shows its worth again. Feels like some parentheses could be golfed out somehow.

The fact that prod() of an empty numeric evaluates to 1 is the only reason this is efficient.

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

Burlesque, 24 bytes

psJ{{1j}qfcqpd}M-jNBL[!!

Try it online!

ps     # Parse to list
J      # Duplicate
{
 {1j}  # Push 1 & swap
 qfc   # Find least common element
 qpd   # Product
}M-    # Create array applying each function to make each element
       # {{Original list}, 1, least common, product}
jNB    # Remove duplicates from original list
L[     # Find length
!!     # Select that element from the array 
       # (zero indexed, hence the push swap to fill zero)

Burlesque, 31 bytes

psJU_qpd{f:{-]1==}fe[~}IEisq1if

Try it online!

Can probably be golfed further.

ps      # Parse to array
JU_     # (Non-destructive) is each element unique?
qpd     # boxed product
{
 f:     # Frequency (returns {{count val} ...})
 {
  -]1== # Count == 1
 }
 fe     # Find element where
 [~     # Take the tail
}
IE      # If unique then product, else find single
is      # Is an error (i.e. single not found)
q1      # boxed 1
if      # If error, push 1
\$\endgroup\$
2
\$\begingroup\$

Mathematica, 40 bytes

f[l_]:=Times@@(If[Count[l,#]<2,#,1]&/@l)

You can try it online!

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

Python 2, 52 bytes

l=input();r=1
for x in l:r*=1%l.count(x)or x
print r

Try it online!

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

Bash + GNU utilities, 26

sort|uniq -u|dc -e1?*?*?*p

The 3 input integers are each given on their own line.

In the case of non-distinct inputs, dc warnings are printed to stderr. These may be ignored.

uniq -u does most of the heavy lifting here. With the -u option, only non-duplicated lines are returned. uniq requires its input to be sorted.

The dc expression pushes 1 to the stack, then reads up to 3 integers, multiplying each in turn, then printing the output. If uniq pipes less than 3 integers to dc, then the surplus ? will not add to the stack and the following * will spit out a warning because * needs to pop 2 operands from the stack. But these are just warnings, dc continues execution until it prints the final product.

Try it online!

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

Python 3, 63 62 61bytes

lambda l:prod(x for x in l if l.count(x)<2)
from math import*

You can try it online!

Thanks @FryAmTheEggman for saving me 1 byte.

\$\endgroup\$
  • 1
    \$\begingroup\$ You can use <2 instead of ==1. I also recommend looking through the code review responses - some of them can make for good golfing! :) \$\endgroup\$ – FryAmTheEggman Feb 10 at 18:44
  • \$\begingroup\$ @FryAmTheEggman thanks! Also, you think so? A first glance didn't show me anything very promising. Most answers used a LOT of if/else or imports... \$\endgroup\$ – RGS Feb 10 at 18:58
  • 1
    \$\begingroup\$ I actually know there is something shorter :) Yours is different and works for any number of arguments, but you can save bytes by using that there are only 3 inputs! (Since it'll be totally different, if you find one I recommend posting another answer) \$\endgroup\$ – FryAmTheEggman Feb 10 at 19:01
  • \$\begingroup\$ @FryAmTheEggman If I do find it, I'll do as you suggest :) \$\endgroup\$ – RGS Feb 10 at 20:09
  • \$\begingroup\$ @FryAmTheEggman shaved 1 more byte but still not what you were talking about \$\endgroup\$ – RGS Feb 10 at 23:32
2
\$\begingroup\$

C#, 60 bytes

int f(int a,int b,int c)=>a==b?a==c?1:c:a==c?b:b==c?a:a*b*c;
\$\endgroup\$
  • \$\begingroup\$ Hi and welcome to code golf! I edited your submission to include the score, since we require that for all posts. I think you can save some bytes by removing some spaces. Good luck and I hope you enjoy your time here :) \$\endgroup\$ – FryAmTheEggman Feb 11 at 19:31
2
\$\begingroup\$

TI BASIC, 46 Bytes

Prompt A,B,C
ABC
If A=B
C
If A=C
B
If B=C
A
If A=B and A=C
1
Disp Ans
\$\endgroup\$
  • \$\begingroup\$ I'm not sure that A=sqrt(BC) is what you want...Suppose A=12, B=9, and C=16. Then A=sqrt(BC), but A!=B and A!=C. \$\endgroup\$ – Giuseppe Feb 12 at 18:59
  • \$\begingroup\$ Yeah that might not be as clean as hoped. I think you can also do prod(A={B,C but that comes out to the same bytes as A=B and A=C \$\endgroup\$ – TiKevin83 Feb 12 at 19:08
2
\$\begingroup\$

Perl 6, 27 bytes

{[*] .Bag.grep(0=>1)>>.key}

Try it online!

(Using a Pair as matcher compares only values and ignores the key.)

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

PHP, 92 79 bytes

fn($a)=>array_product(array_keys(array_intersect(array_count_values($a),[1])));

Try it online!

This isn't going to win for brevity, but just thought I'd try it entirely using chained PHP array functions.

Now using @Guillermo Phillips's suggestion for PHP 7.4 arrow function syntax to save 13 bytes.

PHP, 66 bytes

fn($a,$b,$c)=>$a-$c?$a-$b?$b-$c?$a*$b*$c:$a:$b==$c?:$c:$b==$c?:$b;

Try it online!

And another crazy ternary version inspired by @Guillermo Phillips's answer!

\$\endgroup\$
  • \$\begingroup\$ It's a shame because the functions are powerful but verbose. Also, of course you can always use arrow functions: fn($a)=>..., but that's probably beside the point. \$\endgroup\$ – Guillermo Phillips Feb 13 at 16:17
  • \$\begingroup\$ @GuillermoPhillips Yeah, they certainly weren't named for golfing. array_count_values()? Come on guys! I've avoided the PHP 7.4+ short syntax, though I can't think of a good reason why... perhaps it's time. It's a good suggestion because it actually will save a non-trivial number of bytes. \$\endgroup\$ – 640KB Feb 13 at 16:31
1
\$\begingroup\$

PowerShell, 97 bytes

param($n)$a,$b,$c=$n|group;(($n-join'*'|iex),(($a,$b|?{$_.count-eq1}).name,1)[$a.count-eq3])[!$c]

Try it online!

Not terribly impressive, but given that PowerShell doesn't have a ternary operator like JavaScript, nor the same for structure as Python, I don't think this is too bad.

We take input $n as an array, then feed that into Group-Object, which stores the (potentially) three values into $a, $b, $c. Then we use array-indexing as a pseudo-ternary. We work "backwards" on the function definition given in the challenge, starting from the bottom. If we have a $c, then we have three unique values, so we -join $n with * and iex it (similar to eval). Otherwise, we have at least a duplicate, so we re-index whether $a's .count is -equal to 3. If it is, then all three values are the same, and we output 1. Otherwise, we pull out the lonely value (i.e., its .count is -equal to 1) and output its .name. In any case, the result is left on the pipeline and output is implicit.

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

Perl 5 -MList::Util=product -apl, 45 44 bytes

@FryAmTheEggman saves a byte

$_=product(grep{$t=$_;2>grep$t==$_,@F}@F)||1

Try it online!

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

Charcoal, 11 bytes

IΠEθ⎇⊖№θι¹ι

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

   θ        Input array
  E         Map over elements
      №     Count of
        ι   Current element
       θ    In input array
     ⊖      Decremented
    ⎇       Ternary
          ι If count was 1 then original element
         ¹  Otherwise literal 1
 Π          Take the product
I           Cast to string for implicit print

I found other ways of formulating the condition, but they were all the same length. Alternate approach, also 11 bytes:

IΠ∨Φθ⁼¹№θι¹

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

    θ       Input array
   Φ        Filter where
       №    Count of
         ι  Current element
        θ   In input array
     ⁼      Equals
      ¹     Literal 1
  ∨         Or if list is now empty
          ¹ Then literal 1
 Π          Take the product
I           Cast to string for implicit print
\$\endgroup\$
1
\$\begingroup\$

Retina, 51 bytes

N`\d+
\b(\d+)(,\1)+\b

~["^.*¶$.("|""]'_L$`\d+
$&$*

Try it online! Link includes test cases. Explanation:

N`\d+

Sort the input list.

\b(\d+)(,\1)+\b

Delete all duplicated numbers.

L`\d+

List all the remaining numbers, discarding any commas.

$`
$&$*

Suffix each number with a *.

|""`

Don't separate the numbers.

["^.*¶$.("`

Prefix the result with ^.* on its own line and $.( on the same line as the numbers.

]'_`

Suffix the result with a _.

~`

Evaluate the result on the previous contents of the buffer. This results in one of three evaluations:

  1. If all three numbers were identical, it evaluates this:

    ^.*
    $.(_
    
  2. If two numbers were identical, it evaluates this:

    ^.*
    $.(5*_
    
  3. If the numbers were distinct, it evaluates this:

    ^.*
    $.(1*2*3*_
    

This takes the string _, and repeats it by the remaining numbers in turn, and then takes the length of the result, which is exactly the same as the product of the numbers, or 1 if there were none left.

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

Japt, 9 6 bytes

ü l1 ×

Try it

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

Zsh, 39 bytes

(){i=1
for n;((i*=${(M)#@:#$n}>1?1:n))}

Try it online!

For the first time, I can say that a zsh math function actually won out over a normal program! I knew there was potential when I got a tie a while back, here's the relevant meta post if you want to know more about them.

The meat of this is the loop where we test for distinctness:

${(M)#@:#$n}
${   #     }    # count
${(M)      }    # matches
${    @:#  }    # on the positional parameters.
${       $n}    # against $n
            >1  # more than 1 (not distinct)

We use a ternary to decide to multiply by 1 or n.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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