40
\$\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\$
7
  • \$\begingroup\$ Do we assume the input array contains a unique element and others are the same? \$\endgroup\$ – Amessihel Jul 28 '20 at 14:52
  • \$\begingroup\$ @Amessihel yes, you don't need to check that, it is assumed. \$\endgroup\$ – Charlie Jul 28 '20 at 14:54
  • 7
    \$\begingroup\$ The title feels too long for such a simple operation. Suggested: Odd one out \$\endgroup\$ – Luis Mendo Jul 28 '20 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 '20 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 '20 at 19:19

68 Answers 68

2
\$\begingroup\$

Charcoal, 8 bytes

IΦθ⁼¹№θι

Try it online! Link is to verbose version of code. Works by filtering out elements whose count is not 1. (Singleton list output is allowed by default, although Charcoal's output for a singleton list looks like that of a bare string anyway.) Explanation:

  θ         Input list
 Φ          Filtered where
     №      Count of
       ι    Current element
      θ     In input list
   ⁼¹       Equals literal `1`
I           Cast to string
            Implicitly print
\$\endgroup\$
2
\$\begingroup\$

R, 36 bytes

n=scan();while(sd(n[-T]))T=T+1;n[+T]

Try it online!

Iterates over the indices, calculating the standard deviation of the array with the associated element removed; when the standard deviation is 0, the removed element is the unique value.

This isn't the shortest by a long shot, but it's a neat little R approach.

\$\endgroup\$
1
  • \$\begingroup\$ It's being a wild R battle, but this is a nice idea. :-) \$\endgroup\$ – Charlie Jul 28 '20 at 15:11
2
\$\begingroup\$

R, 30 29 bytes

Edit: -1 byte thanks to Giuseppe, but still a long way to go to catch the current leading R solution...

y=table(scan());names(y[y<2])

Try it online!

Outputs a character string containing the value of the lonely element.

Edit: just realized that this is a worse version of the solution that Robin Ryder already discarded...

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

Japt, 4 bytes

ü l1

Try it

Groups (and sorts) by value and then filters items of length 1.

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

MY, 17 bytes

ωω9Ġ'ƒ⇷(⍉Σ1=⍸ω@⍰←

Try it online!

Explanation

ωω9Ġ'ƒ⇷(⍉Σ1=⍸ω@⍰←
ωω                  push the argument twice
  9Ġ'               push "=" in the codepage
     ƒ              turn it into a function
      ⇷             keeping the left argument the same, and mapping over each element 
       (            apply that
        ⍉           transpose
         Σ          sum (now we have how many times each element occurs)
          1=        whether the elements are 1
            ⍸       the indeces of that
             ω@     the actual element
               ⍰    it's in an array, so pick a random element from it (since theres only one)
                ←   output
\$\endgroup\$
2
\$\begingroup\$

Wolfram Language (Mathematica), 27 bytes

Keys@Select[Counts@#,#<2&]&

Try it online!

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

Retina, 26 25 bytes

.+
*
O`
,A2,-2`
+`_¶_
¶
_

Try it online! Link includes test suite that converts from a comma-separated list to a newline-separated list for ease of use. Uses @xnor's algorithm. Edit: Saved 1 byte thanks to @FryAmTheEggman pointing out that I didn't need to remove the newlines before counting the _s. Explanation:

.+
*

Convert to unary.

O`

Sort.

,A2,-2`

Drop all entries except the first two and the last.

+`_¶_
¶

Subtract the second value from the sum of the first and last. Well, sort of. All this guarantees is that there are no _s left in between the newlines, so the number of remaining _s is the desired result, but without actually specifying where they are.

_

Count the remaining _s as a decimal integer.

\$\endgroup\$
2
  • \$\begingroup\$ I think you can save a byte doing the subtraction with a loop replacing _¶_ with . I tried to save bytes by making the list always 3 elements by using deduplicate stages, but it didn't work out. \$\endgroup\$ – FryAmTheEggman Jul 28 '20 at 19:41
  • \$\begingroup\$ @FryAmTheEggman Thanks; for some reason I thought I had to delete the s... \$\endgroup\$ – Neil Jul 29 '20 at 1:25
2
\$\begingroup\$

Retina 0.8.2, 17 bytes

O`
^(.*¶)\1+

1G`

Try it online! Link includes test suite that converts from a comma-separated list to a newline-separated list for ease of use. Explanation:

O`

Sort the input lines so that the unique line is now either first or last.

^(.*¶)\1+

If the first two lines are identical then remove them and all following identical lines.

1G`

Take the first remaining line.

\$\endgroup\$
1
  • \$\begingroup\$ Very nice! I had held off posting for a while because I felt like I was missing something, glad to see there was something better out there after all :) \$\endgroup\$ – FryAmTheEggman Jul 29 '20 at 1:57
2
\$\begingroup\$

C (gcc), 68 \$\cdots\$ 59 58 bytes

Saved a byte thanks to ceilingcat!!!

c;d;f(l,n)int*l;{for(c=0;--n;)l[n]-*l?d=n:(c=1);n=l[d*c];}

Try it online!

Inputs a pointer to an array of integers and its length.
Returns the unique element.

How

We initialises a flag, c, to zero and go through all the elements starting at the last through to the second. We use the first element as a test value. When we find an element different from the first we cache its index in d. If an element is the same as the first, we set c to one. After looping we know that the first element is unique if c is still zero. Otherwise d is the index of the unique element.

\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat Interesting how the extra braces are worth it - thanks! :-) \$\endgroup\$ – Noodle9 Jul 29 '20 at 8:45
2
\$\begingroup\$

Io, 38 bytes

method(x,x unique sum-x average round)

Try it online!

Explanation

                                       // x = [1,1,2,1,1,1]
method(x,                            )
         x unique                      // Uniquified x: [1,2]
                  sum                  // Sum:          3
                      x average        // Average of x: 1.1666666666666667
                                round  // Round to the closest integer: 1
                     -                 // Minus: 3-1 = 2

Io, 44 bytes

The built-in solution.

method(x,x uniqueCount map(reverse)min last)

Try it online!

Explanation

                                             // e.g. x = [1,2,1,1,1,1]
method(x,                                  ) // Method (taking x):
         x uniqueCount                       // Uniquified counts.   [[1,5],[2,1]]
                       map(reverse)          // Put counts in front. [[5,1],[1,2]]
                                   min       // The one with the smallest count. [1,2]
                                       last  // Return the current item. 2

Io, 44 bytes

(Comparison answer, if I just ported Arnauld's solution anyway)

method(x,x sortInPlace()first+x pop-x at(1))

Try it online!

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

Assembly (as, x64, Linux), 142 bytes (455 bytes code)

This runs on Linux only (for the syscalls) and only respects integers as bytes (input in ASCII).

.intel_syntax noprefix
.text
.global _start
_start:
mov cx,0
r:
lea rbx,a
lea rsi,i
mov rdi,0
mov rdx,2
mov rax,0
push rcx
syscall
pop rcx
mov al,[rsi]
cmp cx,0
je s
cmp cx,1
je t
cmp cx,2
je v
cmp al,[rbx]
jne p
jmp w
s:
mov [rbx],al
inc cx
jmp r
t:
inc cx
cmp al,[rbx]
je r
inc rbx
jmp s
v:
cmp al,[rbx]
je r
mov [rbx+1],al
w:
inc rbx
p:
mov rsi,rbx
mov rdx,1
mov rdi,1
mov rax,1
syscall
mov rdi,0
mov rax, 60
syscall
.data
a:
.byte 0,0
i:
.byte 0,0,0


Try it online!

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Output seems to be the opposite than expected. For [0 1 0] it returns 0 rather than 1. \$\endgroup\$ – Charlie Jul 28 '20 at 17:52
  • \$\begingroup\$ I also saw this on tio but it actually works on my computer. Nevertheless I linked tio to at least make the rest triable :-( \$\endgroup\$ – Gedobbles Jul 28 '20 at 17:54
  • 1
    \$\begingroup\$ Functionality aside, you can compact the code by removing newlines here and there (labels can share a line with a mnemonic). Also, mov [rbx+1],al inc rbx can be changed to inc rbx mov [rbx],al. 438 bytes \$\endgroup\$ – gastropner Jul 28 '20 at 18:31
  • 1
    \$\begingroup\$ x86 answers can be scored by their assembled byte count. codegolf.meta.stackexchange.com/questions/12339/… \$\endgroup\$ – qwr Jul 29 '20 at 6:03
  • \$\begingroup\$ Thanks for the hint, I'll correct that as soon as I'm not on mobile. \$\endgroup\$ – Gedobbles Jul 29 '20 at 8:25
2
\$\begingroup\$

Python 2, 47 bytes

i=sorted(input())
print(i[0],i[-1])[i[0]==i[1]]

Try it online!

A long way from the shortest Python answer but just another way of doing it.

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

PHP, 46 45 bytes

fn($i)=>array_flip(array_count_values($i))[1]

Try it online!

Could maybe be golfed more using a custom solution, but the straightforward one is quite short already: returns the first value that is counted one time. Works with any type of value. If only PHP array functions were not prefixed with array_!

EDIT: saved 1 byte thanks to @640KB now uses array_flip, meaning that it still works for any value type but this time gets the last value counted one time

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Yes, darn those long and redundant function names. Turns out it's 45 bytes if you use array_flip() instead of array_search() though! \$\endgroup\$ – 640KB Jul 29 '20 at 13:27
  • \$\begingroup\$ @640KB nice one! I actually didn't know about array_flip, makes sense! \$\endgroup\$ – Kaddath Jul 29 '20 at 13:53
2
\$\begingroup\$

Dyalog APL, 15 14 bytes

{⍵[⊃⍋+/⍵∘.=⍵]}

-1 byte thanks to @streetster

Try it online!

Explanation

{⍵[⊃⍋+/⍵∘.=⍵]} 
     +/⍵∘.=⍵  - a list of the number of occurences of each element
   ⊃⍋         - grab the first index
 ⍵[         ] - extract that element
\$\endgroup\$
4
  • \$\begingroup\$ Can you add an explanation to the solution? Is there any part of my k solution that can help to golf this? \$\endgroup\$ – streetster Jul 28 '20 at 20:16
  • 1
    \$\begingroup\$ I don't think there's any part of the K solution that will help, but I will surely add an explanation! \$\endgroup\$ – Ada Jul 28 '20 at 20:49
  • 1
    \$\begingroup\$ Can you use 'grade up' to get something like this K solution? {x@*<+/x=\:x} - rather than checking for equality with 1, get indices to sort ascending and take the first? \$\endgroup\$ – streetster Jul 29 '20 at 8:13
  • \$\begingroup\$ Tacit form: ⊢⊃⍨∘⊃∘⍋1⊥∘.=⍨ (TIO) Not so pretty, but saves a byte. \$\endgroup\$ – Bubbler Jul 30 '20 at 2:14
2
\$\begingroup\$

Wolfram Language (Mathematica), 19 bytes

Tr[#/.Median@#->0]&

Inspired by Kirill L.'s R submission

Try it online!

Finds the median, replaces its occurrences in the list with 0, and sums the list.

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

Brain-Flak, 112 bytes

(()){{}({}<{({}<>)<>}<>>){({}<>)<>}<>(({}[({})])<({}({}))>)((){[()]<{{}({}<(({}[({})])<({}{})>)<>{}>)<>}>}{})}<>

Try it online!

Explanation

Very broadly speaking this cycles the list until the first two elements are unequal. Then it deletes the front element until the second two elements are the same. Once that is done it outputs whatever is on the front.

Ok that wasn't quite true. I said

Then it deletes the front element until the second two elements are the same

But it actually deletes the 1st and the 3rd elements until ...

This doesn't actually make a difference to the output though, to see why let's look at the cases. First the easy cases with more than 3 elements

b a a a a ...

In this case the second two elements are equal (a = a) so it stops and outputs b.

a b a a a ...

In this case the second two elements are unequal (a /= b) so it removes the first and third elements.

b a a ...

Now we are back to the first case.

Now for the cases with three elements.

b a a

In this case the second two elements are equal (a = a) so it stops and outputs b.

a b a

In this case the second two elements are unequal (a /= b) so it removes the first and third elements.

b

Now we want to run the check again, but there is only one element. Luckily Brain-Flak pads the bottom of the stack with zeros so this is really the same as

b 0 0

And we assumed input was positive b /= 0 so we are back to the case above.


So that works fine but why do we do it?

The thing about Brain-flak is that in order to do any non trivial checks with an element we need to pop it from the stack. That means that if we want to do things in place, like check if one element is equal to another, we need to pop those things and put them back. So here we save bytes by not putting the third element back when we are checking equality.

This saves us two bytes.

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

Lua, 43 bytes

t=arg table.sort(t)print(t[1]+t[#t]-t[2]|0)

Try it online!

Returning method stolen from Arnauld's solution.

Alternate Solution, 49 Bytes:

t=arg table.sort(t)print(t[t[1]<t[2]and 1or#t]|0)

Notes

Lua's table indexing starts at 1, and boolean logic generally returns the value rather than an actual bool.

\$\endgroup\$
3
  • 1
    \$\begingroup\$ -1: snippets are not allowed. In JS answer you are referring to a function is declared and a is a name of its argument. This is not the case for your answer, which does not declare callable function and uses variables for input and output, which is not allowed as well. \$\endgroup\$ – val is still with Monica Jul 31 '20 at 11:21
  • 1
    \$\begingroup\$ Sorry, was not familiar with the rules when I first started. Fixed to make it a full program. \$\endgroup\$ – Benrob0329 Jul 31 '20 at 16:45
  • 1
    \$\begingroup\$ Great! Turned -1 into +1 now. Also, just learnt that |0 can be used to convert numbers to integers (I knew about //1, but this is new for me). P.S.: it's recommended to use tio.run to provide examples. It also provides code in format that can be directly copied as a Codegolf.SE answer. \$\endgroup\$ – val is still with Monica Jul 31 '20 at 17:19
2
\$\begingroup\$

Python 3, 49 bytes

def f(n):n.sort();return (n[0],n[-1])[n[0]==n[1]]

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ Why are you sorting the input outside your code? (you may not assume the input is sorted because there are test cases where it is not) Also, this does not work correctly even for the test case included in your TIO link... \$\endgroup\$ – the default. Aug 9 '20 at 16:39
  • \$\begingroup\$ @my pronoun is monicareinstate Thank you, for mentioning my blunder, and i corrected the code \$\endgroup\$ – Eesa Aug 9 '20 at 17:50
  • \$\begingroup\$ The second option is wrong. This still doesn't work: Try it online! \$\endgroup\$ – the default. Aug 10 '20 at 2:49
  • \$\begingroup\$ @mypronounismonicareinstate sorry, I oversight it. Edited the code, now it works perfect \$\endgroup\$ – Eesa Aug 10 '20 at 7:37
2
\$\begingroup\$

Arn, 12 bytes

BØ├┤ÅöÀ&iG£3

Explanation

Unpacked: $v{(${=v})#<2}

$ Filter
  v{ block with index named v
    ( Start expression
      $ Filter
        { block with index named _
          =v Is current item equal to v
        }
    )
    # Length
    <2 Is less than 2
  }

Output implicit, input on one line split by spaces

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

JavaScript (61 60 bytes)

My first attempt in this community, so there's room for improvement:
x=>{[a,b,c]=x.filter((e,i)=>x[i-1]!=e);return !c&&x[1]-a?a:b}

x=>{[a,b,c]=x.filter((e,i)=>x[i-1]!=e);return!c&&x[1]-a?a:b}

Try it online!

Explanation:

x.filter((e,i)=>x[i-1]!=e)

The array is filtered to remove any element that is the same as array[index - 1]. These are then unpacked into variables [a,b,c].
The three scenarios are 1) [same, unique, same] 2) [unique, same] 3) [same, unique]

return !c&&x[1]-a?a:b

If c is undefined, i.e. the unique element was on the end of the array - and if 'a' (which is by now either array[0] or array[last element - 1]) is not equal to array[1], then a is the unique element. Otherwise, we have scenario 1 or 3, either way - return 'b'

\$\endgroup\$
3
  • \$\begingroup\$ Welcome to the wonderful world of code golf! I look forward to seeing more of your posts! \$\endgroup\$ – Lyxal Aug 13 '20 at 23:56
  • \$\begingroup\$ Also, -1 byte by removing the space between return and ! \$\endgroup\$ – Lyxal Aug 13 '20 at 23:57
  • \$\begingroup\$ Thanks, not sure how I missed that whitespace lol. \$\endgroup\$ – Scott Aug 15 '20 at 1:22
2
\$\begingroup\$

Desmos, 169 105 42+24=66 bytes

Far from a competing answer, but I just wanted to add an interesting language to here:

Expression 1, 42 bytes

f(a)=b[1]+b[\operatorname{length}(a)]-b[2]

Expression 2, 24 bytes

b=\operatorname{sort}(a)

Try it on Desmos!

If anyone more advanced in Desmos could help me, I would appreciate it(I'm just a beginner)! The one thing that I think could really shave off a lot of bytes is replacing some of the repeated things with a single variable, like b=\operatorname{sort}(a), and then just replace \operatorname{sort}(a) with b everywhere. But I couldn't find a way to declare variables inside a function, so I couldn't do that.

Ok this "exploit" somehow works, even though it's throwing an error.

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

C (gcc), 48 46 44 bytes

-2 thanks to @ceilingcat

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

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ @ceilingcat thank you! \$\endgroup\$ – Sheik Yerbouti Jan 20 at 12:09
1
\$\begingroup\$

Perl 5 -a, 33 bytes

1-(@b="@F"=~/\b$_\b/g)||say for@F

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Note that in the input every element must be the same except one, so [1 2 3 4 4 3 1 1] would not be a valid input. \$\endgroup\$ – Charlie Jul 28 '20 at 14:26
  • \$\begingroup\$ Changed my test case, but it doesn't really matter to the code. It finds the unique element either way. \$\endgroup\$ – Xcali Jul 28 '20 at 14:34
1
\$\begingroup\$

Japt -m, 4 bytes

ü l1

Try it

ü       sort and group
  l1    take lenght 1 result
\$\endgroup\$
1
\$\begingroup\$

Retina, 24 bytes

N`
L0`^(\d+)(?!¶\1)|\d+$

Try it online!

This works by sorting the input (one number per line) and then outputting the first number if it is different from the second, and otherwise outputting the last number.

The test case code was taken from Neil's Retina answer which uses an arithmetic method to determine the answer after sorting.

\$\endgroup\$
1
  • \$\begingroup\$ You inspired me to write an answer which could be backported to Retina 0.8.2, and was shorter to boot! \$\endgroup\$ – Neil Jul 29 '20 at 1:51
1
\$\begingroup\$

Google Sheets, 28

Closing parens already discounted.

  • Column A is input.
  • B1 - =SORT(A:A)
  • B2 - =FILTER(B:B,B:B<>B2)

Excel 2016, 35

  • Column A is input.
  • B1 - =MAX(A:A)
  • B2 - =IF(MODE(A:A)-B1,B1,MIN(A:A))

If the mode is the same as the max, then it's the min, otherwise max.

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

Burlesque, 8 bytes

psf:<][~

Try it online!

Explanation:

ps       # Parse input string as a block
  f:     # Frequency list - returns block of blocks with format {frequency value}
    <]   # Take the minimum block, in this case calculated based on the first element (frequency)
      [~ # Take the last element (value)
         # Implicitly output
\$\endgroup\$
1
\$\begingroup\$

Wolfram Language (Mathematica) 17 29 bytes

Code corrected due to comment by @att:

SortBy[Tally[#],Last][[1,1]]&
\$\endgroup\$
2
  • 3
    \$\begingroup\$ Fails when the unique element is the first element. \$\endgroup\$ – att Jul 28 '20 at 19:22
  • \$\begingroup\$ Yes, Good catch! (I corrected the code.) \$\endgroup\$ – DavidC Jul 29 '20 at 15:04
1
\$\begingroup\$

C# 42 Bytes

r.GroupBy(a=>a).First(a=>a.Count()==1).Key
\$\endgroup\$
3
  • \$\begingroup\$ Welcome to the site. Are you sure C# requires all that whitespace? If it doesn't, removing it could be a easy way to shorten this. \$\endgroup\$ – Wheat Wizard Jul 30 '20 at 2:36
  • \$\begingroup\$ @AdHocGarfHunter Thanks! You're right. Have edited it further \$\endgroup\$ – primmslim Jul 30 '20 at 2:56
  • 1
    \$\begingroup\$ Also if I understand the code correctly groups can't be size zero? So <2 should be a shorter way of checking ==1. If you want tips for golfing in C# from someone who actually knows C# we have a tips page for the language. \$\endgroup\$ – Wheat Wizard Jul 30 '20 at 3:00
1
\$\begingroup\$

Pyth - 6 bytes

I'm not quite sure why this doesn't return an array.

f!t/QT

Explanation

f!t/QT
f!t/QTQ implicit Q added
f     Q filter on each element T of input for 
   /QT  number of times t appears in input
  t     minus 1
 !      is equal to zero
\$\endgroup\$
1
  • \$\begingroup\$ Made me chuckle a bit. \$\endgroup\$ – Razetime Aug 3 '20 at 14:28

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.