35
\$\begingroup\$

Guidelines

Task

Write a method that takes an array of consecutive (increasing) letters as input and that returns the missing letter in the array (lists in some languages).


Rules

  • This is code golf so the shortest answer in bytes wins!
  • You will always get a valid array
  • There will always be exactly one letter missing
  • The length of the array will always be at least 2.
  • The array will always contain letters in only one case (uppercase or lowercase)
  • You must output in the same case (uppercase or lowercase) that the input is
  • The array will always only go one letter a time (skipping the missing letter)
  • The array length will be between 2 and 25
  • The first or last element of the array will never be missing

Examples

['a','b','c','d','f'] -> 'e'

['O','Q','R','S'] -> 'P'

['x','z'] -> 'y'

['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','w','x','y','z'] -> 'v'

\$\endgroup\$
10
  • \$\begingroup\$ Can I take a string instead? \$\endgroup\$
    – Leaky Nun
    Commented Jul 17, 2017 at 7:41
  • \$\begingroup\$ @LeakyNun Strings are arrays of characters, so yes. \$\endgroup\$
    – aimorris
    Commented Jul 17, 2017 at 7:42
  • 1
    \$\begingroup\$ Can the output be an array containing the missing character (e.g: for the input ['a','b','c','d','f','g'], output ['e'], if that makes the code shorter? \$\endgroup\$
    – Mr. Xcoder
    Commented Jul 17, 2017 at 8:59
  • 1
    \$\begingroup\$ @Mr.Xcoder A string is just an array of characters, so yes \$\endgroup\$
    – aimorris
    Commented Jul 17, 2017 at 9:02
  • 3
    \$\begingroup\$ Rule four is simply a subset of rule eight and can be removed (at least, if you put the word "inclusive" at the end of rule eight). \$\endgroup\$
    – NH.
    Commented Jul 17, 2017 at 19:13

68 Answers 68

12
\$\begingroup\$

C# (.NET Core), 48 47 46 bytes, input as char array

s=>{for(int i=0;s[++i]==++s[0];);return s[0];}

Try it online!

Explanation: the first element in the array is incremented as well as a pointer iterating the following elements. When both the first element and the current element are different, it returns the first element.

C# (.NET Core), 58 56 50 bytes, input as string

s=>{var c=s[0];while(s.IndexOf(++c)>=0);return c;}

Try it online!

Previous 58-byte solution (referenced in the first comment):

s=>{for(int i=1;;i++)if(s[i]-s[0]>i)return(char)(s[i]-1);}

Algorithms using System.Linq

The following algorithms must add using System.Linq; (18 bytes) to the byte count and therefore are longer.

I quite liked this one (52+18 bytes):

s=>{int i=0;return(char)(s.First(c=>c-s[0]>i++)-1);}

And you also have a one-liner (45+18)-byte solution:

s=>(char)(s.Where((c,i)=>c-s[0]>i).First()-1)

And a very clever (37+18)-byte solution, courtesy of Ed'ka:

s=>s.Select(e=>++e).Except(s).First()
\$\endgroup\$
10
  • 1
    \$\begingroup\$ Won't this fail to compile with not all code paths return a value? But +1 for the comparison check with s[i]-s[0], pretty clever! \$\endgroup\$ Commented Jul 17, 2017 at 8:35
  • \$\begingroup\$ @TheLethalCoder It won't fail as the for loop does not have a stop condition, so it will keep iterating until the if condition evaluates to true. \$\endgroup\$
    – Charlie
    Commented Jul 17, 2017 at 8:38
  • 1
    \$\begingroup\$ You can save 8 bytes like this: a=>{int i=0;for(;a[++i]-a[0]<=i;);return--a[i];} (when you take the input as char[]). Not thanks to me btw, thanks to @Nevay's comment on my Java 8 answer. \$\endgroup\$ Commented Jul 17, 2017 at 11:12
  • 1
    \$\begingroup\$ @KevinCruijssen found a way to save two more bytes taking the input as a char array. \$\endgroup\$
    – Charlie
    Commented Jul 17, 2017 at 11:51
  • 1
    \$\begingroup\$ Shorter Linq version: s=>s.Select(e=>++e).Except(s).First() \$\endgroup\$
    – Ed'ka
    Commented Jul 20, 2017 at 10:57
8
\$\begingroup\$

Alice, 10 bytes

/X.
\ior@/

Try it online!

Explanation

This is just a framework for linear programs that operate entirely in Ordinal (string processing) mode:

/...
\.../

The actual linear code is then:

i.rXo@

Which does:

i   Read all input.
.   Duplicate.
r   Range expansion. If adjacent letters don't have adjacent code points, the
    intermediate code points are filled in between them. E.g. "ae" would turn
    into "abcde". For the inputs in this challenge, this will simply insert
    the missing letter.
X   Symmetric set difference. Drops all the letters that appear in both strings,
    i.e. everything except the one that was inserted by the range expansion.
o   Output the result.
@   Terminate the program.
\$\endgroup\$
8
\$\begingroup\$

Ruby, 21 characters

->a{[*a[0]..a[-1]]-a}

Returns a single element array, according to question owner's comment.

Sample run:

irb(main):001:0> ->a{[*a[0]..a[-1]]-a}[['a','b','c','d','f']]
=> ["e"]

Try it online!

\$\endgroup\$
8
\$\begingroup\$

Java 8, 70 57 56 48 46 bytes

a->{for(int i=0;++a[0]==a[++i];);return a[0];}

-14 (70 → 56) and -2 (48 → 46) bytes thanks to @CarlosAlejo.
-8 (56 → 48) bytes thanks to @Nevay.

Explanation:

Try it here.

a->{            // Method with char-array parameter and char return-type
  for(int i=0;  //  Start index-integer at 0 and loop as long as
    ++a[0]      //   the previous character + 1 (by modifying the character at index 0)
    ==a[++i];   //   equals the next character (by raising the index by 1 before checking)
  );            //  End of loop
  return a[0];  //  Return the now modified character at index 0 in the array
}               // End of method
\$\endgroup\$
1
  • 1
    \$\begingroup\$ You can use an implicit cast instead of an explicit cast to save 8 bytes a->{int i=0;for(;a[++i]-a[0]<=i;);return--a[i];}. \$\endgroup\$
    – Nevay
    Commented Jul 17, 2017 at 10:15
7
\$\begingroup\$

Haskell, 33 30 bytes

f a=until(`notElem`a)succ$a!!0

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ until saves a byte: f(a:b)=until(`notElem`a:b)succ a \$\endgroup\$
    – xnor
    Commented Jul 17, 2017 at 8:31
6
\$\begingroup\$

C (gcc), 33 35 36 48 60 bytes

All optimizations should be turned off and only on 32-bit GCC.

f(char*v){v=*v+++1-*v?*v-1:f(v);}

Take input as a string.

Try it online!

\$\endgroup\$
4
  • 2
    \$\begingroup\$ "All optimizations should be turned off and only on 32-bit GCC." is a very roundabout way of saying this doesn't work (only appears to work due to UB) \$\endgroup\$
    – sehe
    Commented Jul 18, 2017 at 19:48
  • \$\begingroup\$ I'd say foo(char*a){return*a+1==a[1]?foo(a+1):++*a;} is pretty good; Only 1 char shorter than the more natural foo(char*a){while(*a+1==a[1])a++;return++*a;} \$\endgroup\$
    – sehe
    Commented Jul 18, 2017 at 19:54
  • \$\begingroup\$ @sehe constant undefined behavior is considered acceptable on PPCG \$\endgroup\$
    – Keyu Gan
    Commented Jul 19, 2017 at 3:07
  • \$\begingroup\$ Suggest ~*v+++*v instead of *v+++1-*v \$\endgroup\$
    – ceilingcat
    Commented Jul 10, 2020 at 23:04
5
\$\begingroup\$

Pyth, 5 bytes

-rhQe

Try it online!

\$\endgroup\$
5
\$\begingroup\$

Python 3, 74 62 58 44 40 bytes

-12 bytes thanks to Erik the Outgolfer. -18 bytes thanks to Leaky Nun. -4 bytes thanks to musicman523.

Takes input as a bytestring.

lambda s:chr(*{*range(s[0],s[-1])}-{*s})

Try it online!

Another cool solution:

lambda s:chr(*{*range(*s[::~-len(s)])}-{*s})
\$\endgroup\$
5
  • 1
    \$\begingroup\$ .difference({*s}) -> -{*s} \$\endgroup\$ Commented Jul 17, 2017 at 8:06
  • 1
    \$\begingroup\$ 60 bytes \$\endgroup\$
    – Leaky Nun
    Commented Jul 17, 2017 at 8:06
  • 1
    \$\begingroup\$ 44 bytes with bytestring \$\endgroup\$
    – Leaky Nun
    Commented Jul 17, 2017 at 8:09
  • 1
    \$\begingroup\$ 2 more bytes \$\endgroup\$ Commented Jul 21, 2017 at 9:13
  • 1
    \$\begingroup\$ Your solution is what I was after but in a far more elegant way \$\endgroup\$ Commented Jul 24, 2017 at 7:27
4
\$\begingroup\$

Mathematica, 46 bytes

Min@Complement[CharacterRange@@#[[{1,-1}]],#]&
\$\endgroup\$
2
  • \$\begingroup\$ I believe that Min@Complement[CharacterRange@@#[[{1,-1}]],#]& would save a byte. \$\endgroup\$ Commented Jul 17, 2017 at 12:27
  • \$\begingroup\$ @LegionMammal978 actually 2! \$\endgroup\$
    – ZaMoC
    Commented Jul 17, 2017 at 12:45
4
\$\begingroup\$

Retina, 33 25 bytes

$
¶$_
T`p`_p`.*$
D`.
!`.$

Try it online! Works with any range of ASCII characters. Edit: Saved 8 bytes thanks to @MartinEnder. Explanation: The first stage duplicates the input. The second decreases all of the characters in the copy by 1 code point. The third stage deletes all of the characters in the copy that still appear in the original. This just leaves the original input, the character that precedes the first character of the original input and the missing character. The last stage then just matches the missing character.

\$\endgroup\$
2
  • \$\begingroup\$ Here is 25, using the same basic idea: tio.run/##K0otycxL/P9fhevQNpV4rpCEgoT4ggQ9LRUulwQ9LsUEPZX///… (I'm decrementing the second line because that saves a byte and then I'm finding the unique char using deduplication.) \$\endgroup\$ Commented Jul 17, 2017 at 14:00
  • \$\begingroup\$ @MartinEnder Deduplication is exactly what I wanted all along, and I already forgot Retina has it, sigh... (I know incrementing the first line takes a byte more than decrementing the second line but it made the match regex shorter.) \$\endgroup\$
    – Neil
    Commented Jul 17, 2017 at 14:53
4
\$\begingroup\$

SWI Prolog, 124 bytes

m([H|T]):-n(H,N),c(T,N),!,m(T).
n(I,N):-o(I,C),D is C+1,o(N,D).
c([N|_],N).
c(_,N):-print(N),!,fail.
o(C,O):-char_code(C,O).

Examples:

?- m(['a','b','c','d','f']).
e
false.

?- m(['O','Q','R','S']).
'P'
false.

?- m(['x','z']).
y
false.

?- m(['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','w','x','y','z']).
v
false.

Little explanation:

The m is the "main" procedure,the n produces next expected character in the list. The c does comparison - if expectation matches the next item, continue, else print out expected character and jump out of the window.

\$\endgroup\$
1
  • 2
    \$\begingroup\$ Shorter than fail: 0=1. \$\endgroup\$
    – mat
    Commented Jul 22, 2017 at 22:28
4
\$\begingroup\$

Husk, 3 bytes

-¹…

Try it online!

I'm slightly nervous about posting this, as it seems wierd to beat all other answers (including one in Husk) by such a significant margin... but it seems to work for the test cases, at least...

How?

-       # output elements that are different between:
 ¹      # 1. the input list, and
  …     # 2. the input list, with all the gaps filled 
        #    with the missing character ranges
\$\endgroup\$
1
  • \$\begingroup\$ yep, it's alright. I thought APL extended had a similar answer, but looks like it's rangify doesn't work with characters. \$\endgroup\$
    – Razetime
    Commented Nov 6, 2020 at 16:58
3
\$\begingroup\$

JavaScript (ES6), 70 bytes

Input as a character array

(a,p)=>a.some(c=>(q=p+1,p=c.charCodeAt(),p>q))&&String.fromCharCode(q)

Less golfed

a=>{
  p = undefined;
  for(i = 0; c = a[i]; i++)
  {
    q = p+1
    p = c.charCodeAt()
    if (p>q)
      return String.fromCharCode(q)
  }
}

Test

F=(a,p)=>a.some(c=>(q=p+1,p=c.charCodeAt(),p>q))&&String.fromCharCode(q)

function update() {
  var a0=A0.value.charCodeAt()
  var a1=A1.value.charCodeAt()
  if (a1>a0) {
    var r = [...Array(a1-a0+1)]
      .map((x,i)=>String.fromCharCode(a0+i))
      .filter(x => x != AX.value)
    I.textContent = r.join('') + " => " + F(r)
  }
  else {
    I.textContent=''
  }
}

update()
input { width: 1em }
Range from <input id=A0 value='O' pattern='[a-zA-Z]' length=1 oninput='update()'>
to <input id=A1 value='T' pattern='[a-zA-Z]' length=1 oninput='update()'>
excluding <input id=AX value='Q' pattern='[a-zA-Z]' length=1 oninput='update()'>
<pre id=I></pre>

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

PHP>=7.1, 46 bytes

Take input as string

<?=trim(join(range(($a=$argn)[0],$a[-1])),$a);

PHP Sandbox Online

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

Excel, 110 + 2 = 112 bytes

=CHAR(CODE(LEFT(A1))-1+MATCH(0,IFERROR(FIND(CHAR(ROW(INDIRECT(CODE(LEFT(A1))&":"&CODE(RIGHT(A1))))),A1),0),0))

Must be entered as an array formula (Ctrl+Shift+Enter) which adds curly brackets { } on each end, adding two bytes. Input is as a string in A1, which is OK per OP.

This is not the shortest answer by far (Excel rarely is) but I like seeing if it can be done.

\$\endgroup\$
2
  • \$\begingroup\$ For you to consider if input is an actual array: =XLOOKUP(2,CODE(A2:A5)-CODE(A1:A4),CHAR(CODE(A1:A4)+1)). Depending on an array of just two values (e.g.: =XLOOKUP(2,CODE(A2)-CODE(A1),CHAR(CODE(A1)+1)) this would be 46 bytes. Btw, I'm new to this code-golf community but your Excel-answers are nice to go over. Good work! \$\endgroup\$
    – JvdV
    Commented Sep 5, 2022 at 14:37
  • \$\begingroup\$ @JvdV Good work and I appreciate the appreciation. Excel seems rare around here. XLOOKUP was added in 2019 which is after the question was posted. Those answers are allowed but I'll leave this one up. I encourage you to post that as your own answer, though! \$\endgroup\$ Commented Sep 6, 2022 at 15:29
3
\$\begingroup\$

Husk, 6 bytes

→S-(ḣ→

Try it online!

This function takes a string (list of characters) as input, and returns a character as output.

Explanation

→S-(ḣ→
    ḣ→    Get the list of all characters from the null byte to the last character of the input
 S-       Subtract the input from this list
→         Get the last element of the result
\$\endgroup\$
3
\$\begingroup\$

C++14, standard library, generic container type (87 86 bytes)

[](auto a){return++*adjacent_find(begin(a),end(a),[](auto a,auto b){return a+1!=b;});}

Container type from namespace ::std is assumed (e.g. std::string, std::list or std::vector. Otherwise using namespace std; or similar would be assumed.

Thanks to @Ven, with a little bit of preprocessor hacking, you get get it down to 82 bytes (1 newline)

#define x [](auto a,int b=0){return++
x *adjacent_find(begin(a),end(a),x a!=b;});}

See it Live On Coliru

C++14 no standard library (still generic, 64 63 bytes)

[](auto& a){auto p=*begin(a);for(auto c:a)if(c!=p++)return--p;}

Again, need to help name lookup only if container type not from namespace ::std (or associated with it)

Live On Coliru for std::string e.g.

Live On Coliru for char const[] e.g.

\$\endgroup\$
2
  • \$\begingroup\$ You need to put a space between the strike-out text and the next text. \$\endgroup\$
    – CJ Dennis
    Commented Jul 19, 2017 at 7:28
  • \$\begingroup\$ @CJDennis Done. By the way, your current rep (2469) is a beautiful number (being 3*823 and also visually paired as (24)(69) which is (2 2 2 3)(3 23)) \$\endgroup\$
    – sehe
    Commented Jul 19, 2017 at 13:53
3
\$\begingroup\$

Jelly, 6 bytes

O‘Ọḟ⁸Ḣ

Try it online!

How it works

O‘Ọḟ⁸Ḣ - Main link. Takes a string S on the left
O      - Convert to char codes
 ‘     - Increment each
  Ọ    - Convert from char codes

         This yields the characters that directly follow each character in S
         Call this C

    ⁸  - Yield S
   ḟ   - Remove the characters from C that are in S
     Ḣ - Return the first one
\$\endgroup\$
3
\$\begingroup\$

Arturo, 21 bytes

$->s[--@s\0..last<=s]

Try it!

$->s[            ; a function taking an argument s
    <=s          ; duplicate s
    last         ; last letter in s
    ..           ; range
    s\0          ; first letter in s
    @            ; reify range
    --           ; set difference (between the range and duplicated s)
]                ; end function
\$\endgroup\$
3
  • \$\begingroup\$ Could you post an explanation for this? \$\endgroup\$
    – south
    Commented Jun 26, 2023 at 6:35
  • 1
    \$\begingroup\$ @south Affirmative! \$\endgroup\$
    – chunes
    Commented Jun 26, 2023 at 7:42
  • \$\begingroup\$ Not what I was expecting. Love it, Arturo looks very cool. \$\endgroup\$
    – south
    Commented Jun 27, 2023 at 0:03
3
\$\begingroup\$

Uiua SBCS, 9 bytes

⊢▽¬⊃∊∘⊸+1

Try it!

⊃∊∘ can be replaced with ⤚∊ for -1 byte once comes out of experimental.

Explanation

⊢▽¬⊃∊∘⊸+1­⁡​‎⁠‎⁡⁠⁢⁤‏⁠‎⁡⁠⁣⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁤‏⁠‎⁡⁠⁢⁡‏⁠‎⁡⁠⁢⁢‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁣‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢‏‏​⁡⁠⁡‌⁢⁢​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌­
       +1  # ‎⁡increment input
      ⊸    # ‎⁢keeping original input underneath
   ⊃∊∘     # ‎⁣membership mask, keeping incremented input underneath
  ¬        # ‎⁤invert mask
 ▽         # ‎⁢⁡keep
⊢          # ‎⁢⁢first
\$\endgroup\$
2
\$\begingroup\$

Charcoal, 18 bytes

Fγ¿¬∨∨‹ι⌊θ›ι⌈θ№θιι

Try it online! Link is to verbose version of code. Takes input as a string. Works with any almost contiguous sequence of ASCII characters.

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

C#, 104 bytes

using System.Linq;a=>(char)Enumerable.Range(a.Min(),a.Max()-a.Min()).Except(a.Select(c=>(int)c)).First()

Full/Formatted version:

using System.Linq;

namespace System
{
    class P
    {
        static void Main()
        {
            Func<char[], char> f = a =>
                (char)Enumerable.Range(a.Min(), a.Max() - a.Min())
                                .Except(a.Select(c=>(int)c))
                                .First();

            Console.WriteLine(f(new[] { 'a', 'b', 'c', 'd', 'f' }));

            Console.ReadLine();
        }
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ A very clever Linq version by Ed'ka: s=>s.Select(e=>++e).Except(s).First() \$\endgroup\$
    – Charlie
    Commented Jul 20, 2017 at 11:13
  • \$\begingroup\$ @CarlosAlejo I saw you added it to your answer so I won't update mine but yes it is very clever. A lot shorter than my version of doing it. \$\endgroup\$ Commented Jul 20, 2017 at 11:14
2
\$\begingroup\$

APL (Dyalog), 17 bytes

(⊃⎕AV/⍨∨\∧~)⎕AV∘∊

Try it online!

⎕AV∘∊ Boolean: each character in the Atomic Vector (character set) member of the argument?

() apply the following tacit function:

 the first element of

⎕AV the Atomic Vector (the character set)

/⍨ which

∨\ follows the initial (member of the argument)

 but

~ is not (a member of the argument)

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

Python 3, 42 bytes

f=lambda a,*r:r[0]-a>1and chr(a+1)or f(*r)

Try it online!

Uses unpacked bytestring as input: f(*b'OQRS')

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

Rexx (Regina), 56 bytes

a=arg(1)
say translate(xrange(left(a,1),right(a,1)),'',a)

Try it online!

Finally one that enables REXX to use its strong string-manipulation.

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

CJam, 6 bytes (full program) / 7 bytes (code block)

q),^W=

Try it online!

This is a full CJam program that reads the input string from standard input and prints the missing letter to standard output. CJam doesn't actually have "methods", which is what the challenge asks for, but the closest thing would probably be an executable code block, like this:

{),^W=}

Try it online!

This code block, when evaluated, takes the input as a string (i.e. an array of characters) on the stack, and returns the missing character also on the stack.


Explanation: In the full program, q reads the input string and places it on the stack. ) then pops off the last character of the input string, and the range operator , turns it into an array containing all characters with code points below it (including all letters before it in the alphabet). Thus, for example, if the input was cdfgh, then after ), the stack would contain the strings cdfg (i.e. the input with the last letter removed) and ...abcdefg, where ... stands for a bunch of characters with ASCII codes below a (i.e. all characters below the removed last input letter).

The symmetric set difference operator ^ then combines these strings into a single string that contains exactly those characters that appear in one of the strings, but not in both. It preserves the order in which the characters appear in the strings, so for the example input cdfg, the result after ),^ will be ...abe, where ... again stands for a bunch of characters with ASCII codes below a. Finally, W= just extracts the last character of this string, which is exactly the missing character e that we wanted to find (and discards the rest). When the program ends, the CJam interpreter implicitly prints out the contents of the stack.


Bonus: GolfScript, 6 bytes (full program)

),^-1>

Try it online!

It turns out that nearly the same code also works in GolfScript. We save one byte in the full program version due to GolfScript's implicit input, but lose one byte because, unlike CJam's W, GolfScript doesn't have a handy single-letter variable initialized to -1.

Also, CJam has separate integer and character types (and strings are just arrays containing characters), whereas GolfScript only has a single integer type (and has a special string type that behaves somewhat differently from normal arrays). The result of all this is that, if we want the GolfScript interpreter to print out the actual missing letter instead of its ASCII code number, we need to return a single-character string instead of just the character itself. Fortunately, making that change here just requires replacing the indexing operator = with the array/string left truncation operator >.

Of course, thanks to GolfScript's implicit I/O, the code above can also be used as a snippet that reads a string from the stack and returns a single-character string containing the missing letter. Or, rather, any snippet that takes a single string on the stack as an argument, and returns its output as a printable string on the stack, is also a full GolfScript program.

\$\endgroup\$
2
  • 6
    \$\begingroup\$ Code snippets are not allowed by default; only functions and full programs are. So you probably need that q (program), or {...} (block). +1 for the approach though \$\endgroup\$
    – Luis Mendo
    Commented Jul 17, 2017 at 11:18
  • \$\begingroup\$ This is very clever! \$\endgroup\$ Commented Jul 19, 2017 at 9:12
2
\$\begingroup\$

JavaScript (ES6), 64 bytes

Takes input as a string.

s=>(g=p=>(c=String.fromCharCode(n++))<s[p]?p?c:g(p):g(p+1))(n=0)

How?

  • Initialization: We start with n = 0 and p = 0 and call the recursive function g().

    g = p =>                                   // given p
      (c = String.fromCharCode(n++)) < s[p] ?  // if the next char. c is not equal to s[p]:
        p ?                                    //   if p is not equal to zero:
          c                                    //     step #3
        :                                      //   else:
          g(p)                                 //     step #1
      :                                        // else:
        g(p + 1)                               //   step #2
    
  • Step #1: We increment n until c = String.fromCharCode(n) is equal to the first character of the input string s[0].

  • Step #2: Now that we're synchronized, we increment both n and p at the same time until c = String.fromCharCode(n) is not equal to s[p] anymore.

  • Step #3: We return c: the expected character which was not found.

Test cases

let f =

s=>(g=p=>(c=String.fromCharCode(n++))<s[p]?p?c:g(p):g(p+1))(n=0)

console.log(f('abcdf'))                     // -> 'e'
console.log(f('OQRS'))                      // -> 'P'
console.log(f('xz'))                        // -> 'y'
console.log(f('abcdefghijklmnopqrstuwxyz')) // -> 'v'

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

k, 17 13 bytes

-4 bytes thanks to coltim.

{*(`c$1+x)^x}

Try it online!

Explanation:

{           } /def func(x): # x should be a list of chars
      1+x     /  above  = [ord(c)+1 for c in x]
  (`c$   )    /  above  = [chr(i) for i in above]
          ^x  /  result = [e for e in above if e not in x]
 *            /  return result[0]
\$\endgroup\$
1
  • \$\begingroup\$ I think 4 bytes can be saved (although each function invocation now returns a character instead of a string). \$\endgroup\$
    – coltim
    Commented Dec 30, 2020 at 19:15
2
\$\begingroup\$

MATL, 8 7 bytes

1 byte saved thanks to @Luis

tdqf)Qc

Try it at MATL Online

Explanation

      % Implicitly grab the input as a string
t     % Duplicate the string
d     % Compute the differences between successive characters
q     % Subtract 1 from each element
f     % Get the locations of all non-zero characters (1-based index)
)     % Extract that character from the string
Q     % Add one to get the next character (the missing one)
c     % Convert to character and display
\$\endgroup\$
0
2
\$\begingroup\$

J, 18 bytes

{.@(>:-.])&.(3&u:)

Same approach as many others.

Try it online!

{.@(>:-.])&.(3&u:)
            (3&u:)  NB. convert to char codes
    >:              NB. increment
        ]           NB. input
      -.            NB. set difference
  @                 NB. then
{.                  NB. take the head
          &.        NB. lastly, perform the inverse of 3&u:, which converts back to char
\$\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.