38
\$\begingroup\$

In this question at Code Review they tried to find the fastest way to return the unique element in an array where all the elements are the same except one. But what is the shortest code that accomplish the same thing?

Goal

Find the unique element in an array and return it.

Rules

  • The input array will contain only integer, strictly positive numbers, so you can use 0 as the end of the input if your language needs it.
  • The size of the array will be at least 3 and will have a finite size. You can limit the size of the array to any limit your language has.
  • Every element in the array will be the same, except for one which will be different.
  • You must output the value (not the position) of the unique element in any standard format. You can output leading or trailing spaces or newlines.
  • You can take the input array in any accepted format.

Examples

Input                   Output
------------------------------
[ 1, 1, 1, 2, 1, 1 ]      2
[ 3, 5, 5, 5, 5 ]         3
[ 9, 2, 9, 9, 9, 9, 9 ]   2
[ 4, 4, 4, 6 ]            6
[ 5, 8, 8 ]               5
[ 8, 5, 8 ]               5
[ 8, 8, 5 ]               5

Winner

This is , so may the shortest code for each language win!

\$\endgroup\$
  • \$\begingroup\$ Do we assume the input array contains a unique element and others are the same? \$\endgroup\$ – Amessihel Jul 28 at 14:52
  • \$\begingroup\$ @Amessihel yes, you don't need to check that, it is assumed. \$\endgroup\$ – Charlie Jul 28 at 14:54
  • 7
    \$\begingroup\$ The title feels too long for such a simple operation. Suggested: Odd one out \$\endgroup\$ – Luis Mendo Jul 28 at 15:05
  • 5
    \$\begingroup\$ @LuisMendo nice title, the thing is that I just wanted to use the same title as the original question at Code Review but changing "fastest" with "shortest". :-) \$\endgroup\$ – Charlie Jul 28 at 15:08
  • 1
    \$\begingroup\$ Suggest adding testcases [8, 8, 5] and [5, 8, 8] since there isn't one were the last element is unique and 3 element arrays are a corner cases in themselves. \$\endgroup\$ – Noodle9 Jul 28 at 19:19

64 Answers 64

16
\$\begingroup\$

Python 3, 27 bytes

lambda x:min(x,key=x.count)

Try it online!

| improve this answer | |
\$\endgroup\$
13
\$\begingroup\$

R, 24 bytes

a=scan();a[a!=median(a)]

Try it online!

| improve this answer | |
\$\endgroup\$
  • 4
    \$\begingroup\$ Alas for the lack of a built-in mode function. \$\endgroup\$ – svavil Jul 28 at 22:32
9
\$\begingroup\$

JavaScript (ES6),  32  27 bytes

Saved 5 bytes thanks to @xnor

a=>a.sort()[0]+a.pop()-a[1]

Try it online!

How?

a.sort() sorts the input array in lexicographical order. We know for sure that this is going to put the unique element either at the first or the last position, but we don't know which one:

[ x, ..., y, ..., x ].sort() -> [ y, x, ..., x ] or [ x, x, ..., y ]

Either way, the sum of the first and the last elements minus the 2nd one gives the expected result:

[ y, x, ..., x ] -> y + x - x = y
[ x, x, ..., y ] -> x + y - x = y

We could also XOR all of them:

a=>a.sort()[0]^a.pop()^a[1]

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Here's a bit of a different strategy that I think works: TIO \$\endgroup\$ – xnor Jul 28 at 15:17
  • \$\begingroup\$ @xnor This is much better indeed! \$\endgroup\$ – Arnauld Jul 28 at 15:21
9
\$\begingroup\$

x86-16 machine code, 14 bytes

Binary:

00000000: 498d 7c01 f3a6 e305 4ea6 7401 4ec3       I.|.....N.t.N.

Listing:

49          DEC  CX             ; only do length-1 compares 
8D 7C 01    LEA  DI, [SI+1]     ; DI pointer to next value 
F3 A6       REPE CMPSB          ; while( [SI++] == [DI++] );
E3 05       JCXZ DONE           ; if end of array, result is second value
4E          DEC  SI             ; SI back to first value
A6          CMPSB               ; [SI++] == [DI++]? 
74 01       JE   DONE           ; if so, result is second value
4E          DEC  SI             ; otherwise, result is first value 
        DONE: 
C3          RET                 ; return to caller 

Callable function, input array in [SI], length in CX. Result in [SI].

Explanation:

Loop through the array until two different adjacent values are found. Compare the first to the third value. If they are the same, the "odd value out" must be the second, otherwise it is the first.

Example:

Input [ 1, 1, 1, 2, 1, 1 ], reduce until different adjacent values are found a = [ 1, 2, 1, 1 ]. If a[0] == a[2] then result is a[1], otherwise result is a[0].

Tests using DOS DEBUG:

enter image description here

enter image description here

enter image description here

enter image description here

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ lea di, [si+1] is the same size but saves instructions. IDK if we could justify taking the array length as "max index", avoiding the dec cx. It's not an "interesting" saving, just calling-convention wanking, so not worth updating your test-result images. And hard to justify; it's so standard to do pointer+length even in asm. Nice idea overall to use rep cmpsb this way. \$\endgroup\$ – Peter Cordes Jul 31 at 3:40
7
\$\begingroup\$

Haskell, 32 bytes

f(x:y)|[e]<-filter(/=x)y=e|1<3=x

Try it online!

Explanation

The code, expanded with variables renamed to be more descriptive.

f (first:rest)
 | [unique] <- filter (/=first) rest = unique
 | 1 < 3 = first

(first:rest) is a pattern match on a list that destructures it into its first element (first) and the list without the first element (rest).

Each line with a | at the front is a case in the function (known as "guards" in Haskell). The syntax looks like functionName args | condition1 = result1 | condition2 = result2 .... There are two cases:

  1. [unique] <- filter (/=first) rest. This asserts that filter (/=first) rest produces a list containing only one element, which we name unique. filter (/=first) rest filters out all elements in rest not equal to first. If we are in this case, then we know that unique is the unique element, and we return it.
  2. 1 < 3. This asserts that 1 is less than 3. Since it's always true, this is a "fallthrough" case. If we reach it, we know that there are at least 2 elements not equal to the first element, so we return first.
| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

APL (Dyalog Extended), 5 bytes

⍸1=¯⍸

Try it online!

Regular Dyalog APL 18.0 has ⍸⍣¯1, but it doesn't work here because it requires the input array to be sorted, unlike Extended's ¯⍸ which allows unsorted input arrays.

How it works

⍸1=¯⍸  ⍝ Input: a vector N of positive integers
       ⍝ (Example: 4 4 6 4)
   ¯⍸  ⍝ Whence; generate a vector V where V[i] is the count of i in N
       ⍝ (¯⍸ 4 4 6 4 → 0 0 0 3 0 1)
 1=    ⍝ Keep 1s intact and change anything else to zero (V1)
       ⍝ (1= 0 0 0 3 0 1 → 0 0 0 0 0 1)
⍸      ⍝ Where; generate a vector W from V1, where i appears V1[i] times in W
       ⍝ (⍸ 0 0 0 0 0 1 → 6)
| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

05AB1E, 2 bytes

ʒ¢

Try it online!

Since 1 is the only truthy integer in 05AB1E, we can just filter (ʒ) on the ¢ount.

There is also the Counter-Mode builtin, which returns the least frequent element in a list at the same bytecount:

.m

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Stax also has a built-in, but it outputs a code point... \$\endgroup\$ – the default. Jul 28 at 15:04
  • \$\begingroup\$ When I read the challenge just yet I had ¢Ï in mind, which is basically the same approach as your first. Didn't think about the least frequent builtin, but that's indeed a nice alternative. :) \$\endgroup\$ – Kevin Cruijssen Aug 4 at 7:01
  • \$\begingroup\$ @KevinCruijssen thats neat, I had the same idea, but couldn't find Ï in the documentation. Maybe I just need to read all commands descriptions at some point ;). \$\endgroup\$ – ovs Aug 4 at 7:27
6
\$\begingroup\$

Bash + coreutils, 12 bytes

sort|uniq -u

Try it online!

| improve this answer | |
\$\endgroup\$
6
\$\begingroup\$

Octave / MATLAB, 19 bytes

@(x)x(sum(x==x')<2)

Try it online!

How it works

@(x)                  % Define a function of x
          x==x'       % Square matrix of all pairwise comparisons (non-complex x)
      sum(     )      % Sum of each column
                <2    % Less than 2? This will be true for only one column
    x(            )   % Take that entry from x
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ this is the same byte count if you were to port the R answer @(x)x(x!=median(x)) \$\endgroup\$ – Giuseppe Jul 28 at 15:32
  • 2
    \$\begingroup\$ @Giuseppe Good idea! And then @(x)x(x~=mode(x)) is two bytes shorter. You should post that yourself \$\endgroup\$ – Luis Mendo Jul 28 at 15:36
  • 1
    \$\begingroup\$ I can't believe I didn't think of that myself!! Thanks! \$\endgroup\$ – Giuseppe Jul 28 at 15:44
5
\$\begingroup\$

R, 25 bytes

a=sort(scan());a[a!=a[2]]

Try it online!

Sort the input, giving a. Now a[2] is one of the repeated values. Keep only the element not equal to a[2].

This ends up 4 bytes shorter than my best shot with a contingency table:

names(which(table(scan())<2))
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ How do you know that a[2] is one of the repeated values and not the unique value? After sorting, the unique value must be either the first or last element. But couldn't a[2] be the last element? \$\endgroup\$ – Stef Jul 29 at 12:05
  • 3
    \$\begingroup\$ @Stef a[2] is the second element (R uses 1-based indexing), and the array of guaranteed to have at least 3 elements. \$\endgroup\$ – Giuseppe Jul 29 at 12:40
  • \$\begingroup\$ Thanks! I didn't know that R used 1-indexing. \$\endgroup\$ – Stef Jul 29 at 12:46
5
\$\begingroup\$

J, 10 8 bytes

1#.|//.~

Try it online!

How it works

 1#.|//.~  input:                  1 1 1 2 1
      /.~  group by itself:        1 1 1 1
                                   2
    |/     insert | (remainder) into both groups:        
                   1 | 1 | 1 | 1 = 0
                   2             = 2
 1#.       sum:                    2
| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

Pyth, 4 bytes

-1 byte thanks to @FryAmTheEggman

ho/Q

Try it online!

Explanation

 o   : Order implicit input
  /Q : by count of the element
h    : then take the first element
| improve this answer | |
\$\endgroup\$
5
\$\begingroup\$

Octave, 17 bytes

@(x)x(x!=mode(x))

Try it online!

2 bytes golfed thanks to Luis Mendo!

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Jelly, 3 bytes

ḟÆṃ

Explanation: (probably) removes all elements that are not the most common element (returned by Æṃ). I don't know why isn't the result a single-element list (perhaps it's a feature I didn't know about?), but that makes this even better.

Try it online!

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ The result of the Link ḟÆṃ is a single-element-list, it's just that when a full-program is run which results in a single-element-list the printed output is what would be printed if that single-element were the result. (i.e. 2RWWW just prints [1,2] rather than [[[[1,2]]]]. \$\endgroup\$ – Jonathan Allan Jul 28 at 17:41
4
\$\begingroup\$

Ruby, 18 bytes

->a{a-[a.sort[1]]}

Try it online!

The unique element will always be the largest or smallest, so remove all copies of the second element.

| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

RAD, 13 bytes

⍵[1⍳⍨+/⍵∘=¨⍵]

The lack of a need for {} in this language really helps.

Try it online!

Explanation

⍵[1⍳⍨+/⍵∘=¨⍵]
     +/⍵∘=¨⍵  count of each element's # of occurrences
  1⍳⍨         first occurrence of a 1
⍵[          ] the argument at that index
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

T-SQL, 40 bytes

Input is a table variable

DECLARE @ table(v int)
INSERT @ values(1),(1),(2),(1)

SELECT*FROM @ 
GROUP BY v
HAVING SUM(1)=1

Another variation

T-SQL, 54 bytes

DECLARE @ table(v real)
INSERT @ values(1),(1),(2),(1)

SELECT iif(max(v)+min(v)<avg(v)*2,min(v),max(v))FROM @
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ This is so straightforward and logical in SQL. Nice! \$\endgroup\$ – 640KB Aug 2 at 13:07
  • \$\begingroup\$ @640KB thanks for your comment. I added a more obscure solution as well, it is a bit longer unfortunately . However this syntax could be converted to other languages and hopefully allow short answers \$\endgroup\$ – t-clausen.dk Aug 3 at 11:10
4
\$\begingroup\$

Brachylog, 4 bytes

oḅ∋≠

Try it online!

Takes a list and returns a singleton list.

Explanation

oḅ∋≠  Input is a list, say [4,4,3,4].
o     Sort: [3,4,4,4]
 ḅ    Blocks of equal elements: [[3],[4,4,4]]
  ∋   Pick a block: [3]
   ≠  This block must have distinct elements (in this case, must have just one).
      Output it implicitly.
| improve this answer | |
\$\endgroup\$
4
\$\begingroup\$

Wolfram Language (Mathematica), 21 19 17 bytes

f[c=a_...,b_,c]=b

Try it online!

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ also Tally[#][[1, 1]] & for 18 \$\endgroup\$ – Kai Jul 30 at 20:27
  • \$\begingroup\$ @Kai Tally lists elements in order of first appearance. That function is equivalent to #[[1]]&. (besides that, it also contains redundant whitespace) \$\endgroup\$ – att Jul 30 at 20:41
  • \$\begingroup\$ oops you're right, didn't test enough, I thought it would sort them by the number of times they appear. White space was inserted when I copied it out of mma \$\endgroup\$ – Kai Jul 30 at 20:54
3
\$\begingroup\$

Gaia, 2 bytes

C⌡

Not a built-in!

C is "count occurrences in list" and is "find the smallest by".

(the footer is "evaluate" and "call the function above", Gaia doesn't seem to evaluate input by default)

Try it online!

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ If Gaia does not evaluate input by default, shouldn't you include that in the answer? Note all the R answers that need to do a scan(). \$\endgroup\$ – Charlie Jul 28 at 15:25
  • \$\begingroup\$ @Charlie This submission is a function, not a full program (for some reason, Gaia actually calls lines of code functions) \$\endgroup\$ – the default. Jul 28 at 15:27
  • \$\begingroup\$ I typically include the e in my Gaia answers, as I feel it's more correct; e↑ always felt like such a gray area to me. I don't think I would have thought of using for this though, this is pretty neat! \$\endgroup\$ – Giuseppe Jul 28 at 15:30
3
\$\begingroup\$

PowerShell, 23 bytes

$args-ne($args|sort)[1]

Try it online!

Takes input by splatting. We apply a filter to the original array getting rid of the dupes by sorting it and taking the 2nd element.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ omg - ($args|group|where count -eq 1).name doesn't even come close :( \$\endgroup\$ – Lieven Keersmaekers Jul 29 at 9:38
  • 2
    \$\begingroup\$ and $args|group|? c* -eq 1|% n* too \$\endgroup\$ – mazzy Jul 29 at 10:45
3
\$\begingroup\$

Haskell, 30 bytes

f(x:y)|elem x y=f$y++[x]|1>0=x

Try it online! Footer stolen from coles answer.

If the first element is not in the remaining list, return it, otherwise rotate it to the end and try again.

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

K (ngn/k), 8 6 bytes

Solution:

*<#'=:

Try it online!

Explanation:

*<#'=: / the solution
    =: / group the input
  #'   / count length of each
 <     / sort ascending
*      / take the first

Extra:

  • -2 bytes thanks to ngn by dropping the lambda
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ *<#'=: is valid too \$\endgroup\$ – ngn Jul 29 at 9:20
  • \$\begingroup\$ Ah nice, I was trying to get it to work without the lambda, will update! \$\endgroup\$ – streetster Jul 29 at 9:26
3
\$\begingroup\$

Java (JDK), 62 bytes

int f(int[] a){Arrays.sort(a);return a[0]+a[a.length-1]-a[1];}

Try it online!

Thanks to JollyJoker for correct way.

Original completely own failing dumb#ss solution:

int f(int[] a){Arrays.sort(a);return a[0];}

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ Nice try, but fails the 1st test case: on [ 1, 1, 1, 2, 1, 1 ] results 1 instead of the required 2. \$\endgroup\$ – manatwork Jul 29 at 1:07
  • \$\begingroup\$ a[0]<a[1]?a[0]:a[a.length-1] \$\endgroup\$ – JollyJoker Jul 29 at 10:26
  • \$\begingroup\$ or a[0]+a[a.length-1]-a[1] \$\endgroup\$ – JollyJoker Jul 29 at 10:48
  • 1
    \$\begingroup\$ Thanks for the input. Trying to play with the Big Bois always makes me look like an #ss. I guess the "New contributor" tag kind of saved me from rougher comments hehe. \$\endgroup\$ – brat Jul 29 at 13:41
  • 2
    \$\begingroup\$ Suggest int[]a instead of int[] a \$\endgroup\$ – ceilingcat Jul 30 at 18:14
3
\$\begingroup\$

C (gcc), 50 42 bytes

f(int*b,int*e){b=(*b^*e--?:f(b,e)^*e)^*e;}

Try it online!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Excel, 14 bytes

Put the numbers in column A, and enter this formula in another column

=UNIQUE(A:A,,1
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Per the community meta, you can actually drop the trailing ) for -1 byte as excel will auto correct it to be there for you :) \$\endgroup\$ – Taylor Scott Jul 30 at 18:11
  • 1
    \$\begingroup\$ Huh, I somehow forgot/didn't know about UNIQUE() when I did this one. Anyway, you can replace TRUE with 1. \$\endgroup\$ – Calculuswhiz Jul 30 at 23:06
  • \$\begingroup\$ @Calculuswhiz good point, thanks. Lol I typed this on my phone so I didn’t even test it first. \$\endgroup\$ – Conor James Thomas Warford Hen Jul 30 at 23:14
3
\$\begingroup\$

C (gcc), 39 bytes

f(int*a){a=*a-*++a?a[*a--!=a[2]]:f(a);}

Try it online!

f(int*a){      // function taking a 0-terminated array pointer.

 a=            // return using eax register trick.
 *a-*++a?      // compare current item with next item :
 a[*a--!=a[2]] // if different we move the pointer by the result of comparing the next item,
:f(a);         // if not we recursively call on the incremented pointer.
}
| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

C GCC, 40 bytes

f(int*a){a=*a^*++a?a[-(*a==a[1])]:f(a);}

Try it online!

Thanks to xibu for -5 bytes!

Thanks to ceilingcat for -2 bytes!

| improve this answer | |
\$\endgroup\$
3
\$\begingroup\$

Husk, 3 2 bytes

-1 byte thanks to Razetime!

◄=

Try it online!

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Python 3, 56 39 bytes

lambda x:[i for i in x if x.count(i)<2]

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Lambdafication gives 39 bytes. (Singleton list is a valid output format by default.) \$\endgroup\$ – Bubbler Jul 28 at 14:36
  • 1
    \$\begingroup\$ You don't need to convert the input to a set, since it doesn't matter how many times you uselessly count the multiple element. \$\endgroup\$ – Neil Jul 28 at 14:36

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.