Find the highest unique digit

Surprisingly we haven't had a simple "find the highest digit" challenge yet, but I think that's a little too trivial.

Given input of a non-negative integer, return the highest unique (ie not repeated) digit found in the integer. If there are no unique digits, your program can do anything (undefined behaviour), other than the numbers that are non unique in the input of course.

The input can be taken as a single integer, a string, or a list of digits.

Test cases

12         -> 2
0          -> 0
485902     -> 9
495902     -> 5
999999     -> Anything
999099     -> 0
1948710498 -> 7


This is so fewest bytes in each language wins!

• Can we take input as a string instead? Jun 28, 2017 at 8:13
• Given the last test case, I think we are forced to take input as a string... (leading zeroes can't be represented in integers)
– Leo
Jun 28, 2017 at 8:14
• @Leo that was my bad actually, basically mashed the numbers on my keyboard, didn't notice the leading zero. But yes, input can be taken as a string Jun 28, 2017 at 8:17
• @Adám "undefined behaviour" generally means you can do anything, including summoning nameless horrors from the void if that saves bytes. Jun 28, 2017 at 8:22
• @MartinEnder in fact I'll happily knock off 50% of your bytes if your code successfully summons cthulhu upon there being no unique digits ;) Jun 28, 2017 at 8:31

05AB1E, 4 3 bytes

Saved 1 byte thanks to Mr. Xcoder notifying that a digit list is valid input.

¢ÏM


Try it online!

Explanation

¢     # count occurrences of each digit in input
Ï    # keep only the digits whose occurrences are true (1)
M   # push the highest

• Wait so in 05AB1E, 2 is not truthy; only 1? :o Jun 29, 2017 at 2:05
• @HyperNeutrino: Correct! Jun 29, 2017 at 6:02
• That seems both very useful and very bothersome... That is interesting :o :D Jun 29, 2017 at 6:05
• @HyperNeutrino: It often comes in handy, but it can be a disadvantage when the challenge says return a truthy value, when a lot of languages can return any positive integer or maybe even a non-empty string. Jun 29, 2017 at 6:27
• A strikethrough on the number for is not easy to see! Jun 29, 2017 at 23:48

Python 3, 40 bytes

Saved 2 bytes thanks to movatica.

lambda i:max(x*(i.count(x)<2)for x in i)


Try it online!

42 bytes

Works for both String and list of digits parameter types. Throws an error for no unique digits, kind of abuses of that spec:

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


Try it online!

Explanation

• lambda i: - Declares a lambda function with a string or list of digits parameter i.
• max(...) - Finds the maximum value of the generator.
• x for x in i - Iterates through the characters / digits of i.
• if i.count(x)<2 - Checks if the digit is unique.
• 40 bytes: lambda i:max(x*(i.count(x)<2)for x in i) May 21, 2019 at 22:00

Alice, 15 bytes

/&.sDo
\i-.tN@/


Try it online!

Explanation

/...
\.../


This is a simple framework for linear code that operates entirely in Ordinal mode (meaning this program works completely through string processing). The unfolded linear code is then just:

i..DN&-sto@


What it does:

i    Read all input as a string.
..   Make two copies.
D    Deduplicate the characters in the top copy.
N    Get the multiset complement of this deduplicated string in the input.
This gives us a string that only contains repeated digits (with one
copy less than the original, but the number of them doesn't matter).
&-   Fold string subtraction over this string, which means that each of
the repeated digits is removed from the input.
s    Sort the remaining digits.
t    Split off the last digit.
o    Print it.
@    Terminate the program.

• -1, doesn't "summoning nameless horrors from the void" if there are no unique digits. ;) (Read: +1, great answer as always.) Jun 28, 2017 at 13:46
• @KevinCruijssen I tried, but it didn't save bytes. Maybe Dark might be a more appropriate language... Jun 28, 2017 at 13:52

Retina, 16 bytes

O.
(.)\1+

!.$ Try it online! Explanation O.  Sort the digits. (.)\1+  Remove repeated digits. !.$


Fetch the last (maximal) digit.

• Too bad Deduplicate doesn't help here :( Jun 28, 2017 at 19:53

Charcoal, 18 12 bytes

Ｆχ¿⁼№θＩι¹ＰＩι


Try it online! (Link to verbose version)

Prints nothing if no solution is found. The trick is that the for loop prints every unique number in the input string, but without moving the cursor, thus the value keeps reprinting itself until the final solution is found.

The previous version printed the characters A to Z when no solution was found, hence the comments:

ＡααＦχＡ⎇⁼№θＩι¹Ｉιααα


Try it online! (Link to verbose version)

• That's an interesting undefined behavior :) Jun 28, 2017 at 8:42
• This sounds Finnish to me :D Jun 28, 2017 at 9:33
• @fedorqui nice to see you here! Yeah, but Charcoal is easier to learn than Jelly or O5AB1E, and it's funnier to use in ASCII-art games. :-) Jun 28, 2017 at 9:37

Husk, 7 bytes

→fo¬hgO


Try it online! (Test suite, crashes on the last test case since it has no unique digits)

This is a composition of functions in point-free style (the arguments are not mentioned explicitely anywhere). Takes input and returns output as a string, which in Husk is equivalent to a list of characters.

Explanation

Test case: "1948710498"

O    Sort:                             "0114478899"
g     Group consecutive equal elements: ["0","11","44","7","88","99"]
fo¬h      Keep only those with length 1*:   ["0","7"]
→          Take the last element:            "7"


*The check for length 1 is done by taking the head of the list (all elements except the last one) and negating it (empty lists are falsy, non-empty lists are truthy).

JavaScript (ES6), 4641 40 bytes

Takes input as a string. Returns RangeError if there are no unique digits.

s=>f=(i=9)=>s.split(i).length-2?f(--i):i


-7 bytes thanks to Rick Hitchcock

-1 byte thanks to Shaggy

Test cases

let f =

s=>g=(i=9)=>s.split(i).length-2?g(--i):i

console.log(f("12")())         // 2
console.log(f("0")())          // 0
console.log(f("485902")())     // 9
console.log(f("495902")())     // 5
//console.log(f("999999")())   // RangeError
console.log(f("999099")())     // 0
console.log(f("1948710498")()) // 7

• Remove the alert for 39 bytes: (s,i=9)=>s.split(i).length-2?f(s,--i):i. You can avoid the stack overflow for 42 bytes: (s,i=9)=>s.split(i).length-2?i&&f(s,--i):i. Jun 28, 2017 at 13:09
• Save a byte with currying: s=>g=(i=9)=>s.split(i).length-2?g(--i):i and then call it with f("12")() Jun 28, 2017 at 14:08

f s=maximum[x|x<-s,[x]==filter(==x)s]


Try it online!

How it works:

  [  |x<-s   ]          -- loop x through the input string s
x                   -- and keep the x where
[x]==filter(==x)s  -- all x extracted from s equal a singleton list [x]
maximum                 -- take the maximum of all the x


R, 41 bytes

function(x,y=table(x))max(names(y[y==1]))


An anonymous function that takes a list of digits, either as integers or single character strings. It precomputes y as an optional argument to avoid using curly braces for the function body. Returns the digit as a string. This takes a slightly different approach than the other R answer and ends up being the tiniest bit shorter! looks like my comment there was wrong after all...

table computes the occurrences of each element in the list, with names(table(x)) being the unique values in x (as strings). Since digits are fortunately ordered the same lexicographically as numerically, we can still use max.

Try it online!

• Nice! I didn't expect doing something with table would be shorter (plus I can never remember how to get names to work). Jun 28, 2017 at 19:35
• <2 for another byte. There should never be a zero in the counts. Jun 28, 2017 at 20:28
• y=table(scan());max(names(y[y<2])) is a few bytes shorter.
Jun 29, 2017 at 8:53

Python 3, 40 bytes

lambda i:max(x+9-9*i.count(x)for x in i)


Only works for lists of digits. The edge case '990' works fine :)

Try it online!

• Welcome to PPCG! Looks like you've got everything down :) Jun 28, 2017 at 23:29

Husk, 3 bytes

►≠O


Try it online!

Explanation

►≠O
O order the elements
►   max by
≠  inequality(selects least frequent elements)
then returns the last of the least frequent elements


Brachylog, 8 bytes

ọtᵒtᵍhth


Try it online!

Explanation

Example input: 495902

ọ          Occurences:    [[4,1],[9,2],[5,1],[0,1],[2,1]]
tᵒ        Order by tail: [[0,1],[2,1],[4,1],[5,1],[9,2]]
tᵍ      Group by tail: [[[0,1],[2,1],[4,1],[5,1]],[[9,2]]]
t    Tail:          [5,1]


APL (Dyalog Unicode), 10 chars = 19 bytes

Method: multiply elements that occur multiple times by zero, and then fine the highest element.

⌈/×∘(1=≢)⌸


⌸ for each unique element and its indices in the argument:

× multiply the unique element

∘() with:

1= the Boolean for whether one is equal to

≢ the tally of indices (how many times the unique element occurs)

⌈/ the max of that

Try it online!

APL (Dyalog Classic), 15 bytes

⌈/×∘(1=≢)⎕U2338


Try it online!

Identical to the above, but uses ⎕U2338 instead of ⌸.

Husk, 9 8 bytes

Thanks to Leo for suggesting a slightly neater solution at the same byte count.

▲‡ȯf=1#


Try it online!

Explanation

  ȯ       Compose the following thre functions into one binary function.
#  Count the occurrences of the right argument in the left.
=1    Check equality with 1. This gives 1 (truthy) for values that
appear uniquely in the right-hand argument.
f      Select the elements from the right argument, where the function
in the left argument is truthy.
Due to the composition and partial function application this
means that the first argument of the resulting function actually
curries # and the second argument is passed as the second
argument to f. So what we end up with is a function which selects
the elements from the right argument that appear uniquely in
the left argument.
‡        We call this function by giving it the input for both arguments.
So we end up selecting unique digits from the input.
▲         Find the maximum.

• ¬← could be more simply =1, same bytecount though :)
– Leo
Jun 28, 2017 at 9:08
• @Leo Ah yeah, I was too lazy to test whether the currying would work without parentheses. I need to trust more in the type inference. ;) Jun 28, 2017 at 9:10

Mathematica, 41 bytes

(t=9;While[DigitCount[#][[t]]!=1,t--];t)&


thanks @Martin Ender

here is Martin's approach on my answer

Mathematica, 35 bytes

9//.d_/;DigitCount[#][[d]]!=1:>d-1&


R, 45 43 bytes

function(x)max(setdiff(x,x[duplicated(x)]))

Try it online!

Takes input as a vector of integers. Finds the duplicated elements, removes them, and takes the maximum. (Returns -Inf with a warning if there is no unique maximum.)

Edited into an anonymous function per comment

• max(x[!duplicated(x)]) is quite a bit shorter, but this is a great answer. I knew the way I was going to do it was not this good. Also you can remove the f= from the beginning, as anonymous functions are perfectly valid answers. Also, you can use TIO to test your functions if you use this format: Try it online! Jun 28, 2017 at 19:06
• Thanks! I think the 'duplicated' function doesn't count the first occurrence of a duplicate element so your version wouldn't quite work Jun 28, 2017 at 19:10
• ah, good point. I almost never use duplicated but I actually thought up another, shorter answer! Jun 28, 2017 at 19:25

Python 2, 39 bytes

lambda l:max(1/l.count(n)*n for n in l)


Try it online!

• I enjoyed this, it’s great!
– user9207
May 19, 2019 at 4:46

Ruby, 42 bytes

->x{(?0..?9).select{|r|x.count(r)==1}[-1]}


Try it online!

• Ruby ties Python :) Jun 28, 2017 at 8:56
• Because 42 is always the answer. :-)
– G B
Jun 28, 2017 at 8:56
• @GB Or is it: ->x{x.chars.select{|r|x.count(r)<2}.max} Jun 28, 2017 at 9:00
• That would be 2 bytes shorter and ruin the whole thing. :-)
– G B
Jun 29, 2017 at 9:02

Bash + coreutils, 30 28 bytes

-2 bytes thanks to Digital Trauma

fold -1|sort|uniq -u|tail -1


Try it online!

Bash + coreutils, 20 bytes

sort|uniq -u|tail -1


Try it online!

If input is given as a list of digits, one per line, we can skip the fold stage. That feels like cheating though.

• Replace grep -o . with fold -1 to save 2 bytes. I agree that an input integer given as a list of digits is stretching the rules too far. Jun 28, 2017 at 18:54
• +1 just because it is bash
– user9207
May 19, 2019 at 18:39

C# (.NET Core), 2797865857 75 bytes

using System.Linq;

n=>n.GroupBy(i=>i).Where(i=>i.Count()<2).Max(i=>i.Key)-48


Try it online!

Thanks @CarlosAlejo

• This does not work with "1948710498" as input (returns "9" instead of "7"), and you must add using System.Linq; to the byte count. Jun 28, 2017 at 9:03
• @CarlosAlejo Oops! Sorry! Just now read the specifications fully. Will edit the solution soon. Jun 28, 2017 at 9:05
• Edited. Are there any optimisations I can make? Jun 28, 2017 at 9:34
• Sure: try using OrderBy(...).Last() instead of .OrderByDescending(...).First(), for instance. Or even better, change your last part with .Max(i=>i.Key) after the Where clause. Jun 28, 2017 at 9:39
• @CarlosAlejo Thanks! Edited. Jun 28, 2017 at 9:41

<>< (Fish), 93 bytes

0l1-l2-$:?v~~o; v&]{[-3lr < |.!01~$r&\
>r$1-:?!v$rl3-[{]:&:&=?^
@&::&:$~/|.!01$}&~$?(  Try it in my interpreter Found a fun bug in my interpreter testing this Expects input pre-pushed to the stack Explanation Top row: Setup. Push 0, the current maximum, l-1, the total number of iterations of the outer loop, and l-2, the total number of iterations in the inner loop. Initially both are the same. Second row left: Shift left 1, then move the top item to the register. This is the candidate largest member. Third row: Compare the register for each digit. If none match go down. Otherwise go up to second row right. Second row right: Reset, then try another digit. This happens if the digit is equal to another. Last row: We have found a unique digit! Now we check if it's better than the current max value, if so replace it. Then reset and jump to the start. JavaScript (ES6), 52 50 bytes Takes input as a list of digits. Returns 0 if there are no unique digits. s=>s.reduce((m,c)=>m>c|s.filter(x=>x==c)[1]?m:c,0)  Test cases let f = s=>s.reduce((m,c)=>m>c|s.filter(x=>x==c)[1]?m:c,0) console.log(f([1,2])) // 2 console.log(f([0])) // 0 console.log(f([4,8,5,9,0,2])) // 9 console.log(f([4,9,5,9,0,2])) // 5 console.log(f([9,9,9,9,9,9])) // (0) console.log(f([9,9,9,0,9,9])) // 0 console.log(f([1,9,4,8,7,1,0,4,9,8])) // 7 Java (OpenJDK 8), 8985 79 bytes a->{int i=10,x[]=new int[i];for(int d:a)x[d]++;for(;i-->0&&x[i]!=1;);return i;}  Try it online! -6 bytes thanks to @KevinCruijssen's insight! • You can replace return i>0?i:0; with return i;. The output will be -1 for test case [9,9,9,9,9,9], but that is fine with the challenge: "If there are no unique digits, your program can do anything (undefined behavior).". Jun 28, 2017 at 13:43 • Indeed, I can since the current revision. Before I couldn't because of the test case 0. It's something I oversaw in the previous golf! :) Jun 28, 2017 at 13:45 APL (Dyalog), 14 bytes -2 thanks toTwiNight. ⌈/⊢×1=(+/∘.=⍨)  ⌈/ the largest of ⊢ the arguments × multiplied by 1=() the Boolean for each where one equals +/ the row sums of ∘.=⍨ their equality table Try it online! • Since 0 is never the highest unique digit except for 0 itself, you can save 1 byte using × instead of /⍨, then save another byte converting that into a train Jun 29, 2017 at 1:38 • @TwiNight Nice! Thank you. – Adám Jun 29, 2017 at 6:27 PHP, 40 bytes <?=array_flip(count_chars($argn))[1]-48;


Try it online!

PHP, 42 bytes

<?=chr(array_flip(count_chars($argn))[1]);  Try it online! • -2 bytes: <?=array_flip(count_chars($argn))[1]-48; Jul 15, 2017 at 8:40

Java (JDK), 67 bytes

s->{int i=9;for(s=" "+s+" ";s.split(i+"").length!=2;i--);return i;}


Try it online!

J, 16 12 bytes

0{\:~-.}./.~


Try it online!

• This is really nice, and since "The input can be taken as a single integer, a string, or a list of digits." you can actually do 0{\:~-.}./.~ for 12: Try it online! Jun 2, 2019 at 1:29

Japt-h, 121110 4 bytes

I/O as a digit array.

ü l1


Try it

APL (NARS2000) 16 chars, 23(?) bytes

{↑⌽⍸1=+⌿⍵∘.=⍳10}


(input as array of digits, e.g. {↑⌽⍸1=+⌿⍵∘.=⍳10}4 9 5 9 0 2)

Desmos, 113 bytes

U(l)=max([min([\left\{l[n]=l[i]:-1,l[n]\right\} for i=join([0...n-1],[n+1...l.length+1])]) for n=[1...l.length]])
`

Takes input as a list.

Try it out and see versions that make slightly more sense