40
\$\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\$
0

48 Answers 48

12
\$\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\$
1
  • \$\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\$ Feb 11, 2020 at 7:26
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\$
8
  • 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, 2020 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, 2020 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, 2020 at 19:37
  • 1
    \$\begingroup\$ @79037662 Well done - we got there! :-) \$\endgroup\$
    – Noodle9
    Feb 10, 2020 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, 2020 at 9:51
10
\$\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\$
2
  • 1
    \$\begingroup\$ Thanks for including the second solution. It's way cooler than the fully golfed version. \$\endgroup\$
    – emegolf123
    Feb 10, 2020 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, 2020 at 5:48
7
\$\begingroup\$

J, 10 bytes

*/@-.}./.~

Try it online!

     }./.~  group by value and remove one from each group
   -.       set subtract from input
*/          product
\$\endgroup\$
1
  • \$\begingroup\$ This is quite nice \$\endgroup\$
    – Jonah
    Feb 11, 2020 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\$
1
  • 1
    \$\begingroup\$ These days (18.0+), ×/∪*=Ö≢⌸ works. \$\endgroup\$
    – Adám
    Jun 6, 2021 at 4:05
6
\$\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\$
2
  • \$\begingroup\$ Very nice! I only found the 51 :) \$\endgroup\$ Feb 11, 2020 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, 2020 at 8:49
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\$
6
  • 1
    \$\begingroup\$ I had the obvious 47 bytes with duplicated; I did not even come close to this approach! \$\endgroup\$
    – Giuseppe
    Feb 10, 2020 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\$ Feb 11, 2020 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\$ Feb 11, 2020 at 14:55
  • 1
    \$\begingroup\$ @RobinRyder I was massively overcomplicating my indexing at the ends, so here's 36: Try it online! \$\endgroup\$ Feb 11, 2020 at 15:38
  • 1
    \$\begingroup\$ @CriminallyVulgar Well done! Worth posting separately IMO. \$\endgroup\$ Feb 11, 2020 at 16:28
4
\$\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\$
2
  • \$\begingroup\$ @FryAmTheEggman was it that? \$\endgroup\$ Feb 10, 2020 at 21:11
  • 2
    \$\begingroup\$ Basically, just reordered: œ-QɓḟP \$\endgroup\$ Feb 10, 2020 at 21:21
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\$
1
  • \$\begingroup\$ How about =PRODUCT(IFERROR(UNIQUE(A1#,,1),1))? \$\endgroup\$
    – Axuary
    Jun 5, 2021 at 20:55
4
\$\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\$
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\$
5
  • \$\begingroup\$ Think you can -1 byte removing the $n= tio.run/##LcixCoAgEAbgl/kHDR2CXLTwQaLh7ojcFIte/… \$\endgroup\$
    – 640KB
    Feb 13, 2020 at 16:44
  • \$\begingroup\$ And here's a ternary version without the sort()! tio.run/##Vc9Ba4MwFAfw8/Ip/… \$\endgroup\$
    – 640KB
    Feb 13, 2020 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\$ Feb 13, 2020 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, 2020 at 17:19
  • \$\begingroup\$ though it only works when you want to end with a 1. The subtraction is better for the upper leaves. \$\endgroup\$
    – 640KB
    Feb 13, 2020 at 17:23
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
  • 1
    \$\begingroup\$ Ah, that's really clever. I was playing around with something similar, but couldn't get it functional. \$\endgroup\$ Feb 10, 2020 at 20:28
3
\$\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\$
4
  • 2
    \$\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\$ Feb 10, 2020 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, 2020 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\$ Feb 10, 2020 at 19:01
  • \$\begingroup\$ @FryAmTheEggman shaved 1 more byte but still not what you were talking about \$\endgroup\$
    – RGS
    Feb 10, 2020 at 23:32
3
\$\begingroup\$

Wolfram Language (Mathematica), 31 bytes

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

Try it online!

\$\endgroup\$
1
  • \$\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, 2020 at 3:58
3
\$\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\$
3
\$\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\$
2
  • 1
    \$\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\$ Feb 13, 2020 at 16:17
  • 1
    \$\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, 2020 at 16:31
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\$
0
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\$

Ruby, 38 bytes

->*a{r=1;a.map{|w|(a-[w])[1]&&r*=w};r}

Try it online!

\$\endgroup\$
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\$
1
  • \$\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\$ Feb 11, 2020 at 19:31
2
\$\begingroup\$

TI BASIC, 45 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
Ans
\$\endgroup\$
2
  • \$\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, 2020 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, 2020 at 19:08
2
\$\begingroup\$

Brachylog, 6 bytes

≡ᵍ~gˢ×

Try it online!

 ᵍ        Group elements by
≡         value.
    ˢ     For each group,
  ~g      if it is a singleton list, extract its only element,
    ˢ     else discard it.
     ×    Take the product.
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I'm curious about the "select" (meta?)predicate and your explanation. I am having trouble following as the explanation (and my brief glance at the documentation) makes it seem a bit like just a mapping. When/why does it discard results and what does ~g do for non-singleton lists? \$\endgroup\$ Jan 31, 2021 at 17:46
  • 1
    \$\begingroup\$ @FryAmTheEggman The difference between xᵐ and (where x is any predicate) is that, if x fails on any element, xᵐ fails in its entirety, but discards any and all elements which fail instead. Failing is also what ~g does given a non-singleton list (g wraps its input into a singleton list, ~ inverts it). The utility of failure is backtracking to the most recent choice-point, and ˢ has one internally for that. \$\endgroup\$ Jan 31, 2021 at 23:28
2
\$\begingroup\$

Factor + sets.extras math.unicode, 20 bytes

[ non-repeating Π ]

Try it online!

Factor has a word non-repeating that gives you every element of a sequence that doesn't repeat. Turns out the answer to this question is just taking the product of this.

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

MMIX, 48 bytes (12 instrs)

foo CMP $255,$0,$1
    CMP $3,$1,$2
    BZ  $255,0F     // if(a == b) goto ab
    BZ  $3,1F       // if(b == c) goto bc
    CMP $255,$0,$2
    BZ  $255,2F     // if(a == c) goto ac
    MUL $0,$0,$1    // a *= b
    MUL $0,$0,$2    // a *= c
1H  POP 1,0         // bc: return a
0H  CSZ $2,$3,1     // ab: if(b == c) c = 1
    POP 3,0         // return c
2H  POP 2,0         // ac: return b
\$\endgroup\$
2
\$\begingroup\$

Thunno 2, 4 bytes

cḅịp

Try it online!

Explanation

cḅịp  # Implicit input
c     # Counts of each number
  ị   # Only keep items of the input
 ḅ    # where the count equals 1
   p  # Product of this list
\$\endgroup\$
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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