g | x | w | all
Bytes Lang Time Link
077C#241028T205801ZEzlandin
092AWK241028T160427Zxrs
047Raku241021T133941ZMustafa
029APL241016T180915ZAaron
016Japt v2.0a0241016T233629ZShaggy
038Mathematica241016T152954Zpolfosol
083Java JDK241014T121902ZmastaH
007Vyxal 3241014T145111Zpacman25
01005AB1E241014T090356ZKevin Cr
063R241012T094856Zpajonk
069Ruby241013T145705ZJordan
104Haskell241013T131405ZAntonio
047Perl 5241013T114436ZKjetil S
061Zsh241013T095352Zroblogic
075JavaScript Node.js241012T093002ZArnauld
101Racket241013T020005Zmehbark
137Go241012T151143Zbigyihsu
047Factor241013T001802Zchunes
024APL Dyalog Extended241012T220355ZAdá
016Uiua241012T150327ZjanMakos
070C gcc241012T131540Zjdt
082Google Sheets241012T061404Zdoubleun
067jq Rr241012T115256Zpmf
077JavaScript Node.js241012T033113Zl4m2
062APL+WIN241012T092957ZGraham
095Python 3241012T075717Zmecaneer
068Arturo241012T062543Zchunes
062Retina 0.8.2241012T051130ZNeil
020Charcoal241012T043518ZNeil
6125Vyxal241012T032435Zlyxal

C#, 77 bytes

char F(string i)=>(char)i.ToLower().Where(x=>x>96&x<123).Average(x=>x+.5);

Try it online!

Explanation

char F(string i) => (char) // Cast the result to a char
    i.ToLower() // Lower-case the chars in the string
        .Where(x=> x>96 & x<123) // Ensure the character is valid
        .Average(x=> x+0.5); // Average the characters (and add 0.5 to round up)

AWK, 92 bytes

@load "ordchr";BEGIN{FS=X}{gsub(" ",X);for($0=tolower($0);++i<=NF;)x+=ord($i);$0=chr(x/NF)}1

Try it online!

`

@load "ordchr";              # character manipulation module
BEGIN{FS=X}                  # split every character
{gsub(" ",X);                # remove spaces
for($0=tolower($0);++i<=NF;) # make it lowercase
x+=ord($i);                  # total it up
$0=chr(x/NF)}1               # average and print 

Awk's default rounding should do the trick, but ymmv.

Raku, 47 bytes

Attempt This Online!

(.sum/$_).round.chr with .lc.comb(/<:L>/)>>.ord

APL, 32 30 29 chars

⎕UCS⌊(+/÷≢)⎕UCS⎕A(⊣(/⍨)∊)⍥⎕C⍨

Explanation

⎕UCS⌊(+/÷≢)⎕UCS⎕A(⊣(/⍨)∊)⍥⎕C⍨
               ⎕A           ⍨   ⍝ Take the alphabet on the right and input on the left
                 (      )⍥⎕C    ⍝ Call `lowercase` on each arg before calling new inner train
                   (/⍨)         ⍝ Explode the
                  ⊢             ⍝   input string (right arg)
                       ∊        ⍝   by elements in the left arg
           ⎕UCS                 ⍝ Convert to numbers
     (    )                     ⍝ Find average (choo choo!):
        ÷                       ⍝   divide
      +/                        ⍝   the sum
         ≢                      ⍝   by the tally (count)
    ⌊                           ⍝ Floor
⎕UCS                            ⍝ Convert back to letter

Japt v2.0a0, 16 bytes

v f\l
xc ÷UÊ r d

Try it

v f\l\nxc ÷UÊ r d     :Implicit input of string U
v                     :Lowercase
  f                   :Match
   \l                 :  /[a-z]/g
     \n               :Reassign to U
       x              :Sum of
        c             :  Character codes
          ÷           :Divided by
           UÊ         :  Length of U
              r       :Round
                d     :Character at that codepoint

Mathematica, 38 bytes

FromCharacterCode@Mean@ToCharacterCode

Try it online!

Java (JDK), 91 85 83 bytes

s->(char)(s.toLowerCase().chars().filter(c->c>96&c<123).average().orElseThrow()+.5)

-6 for rounding thanks to jdt

Try it online!

Vyxal 3, 7 bytes

ȦøA∆AøA

Vyxal It Online! why does vyxal 3 not have a round element??? oh well

edit: apparently the letter to number auto-rounds but we still dont have a round element.

05AB1E, 10 bytes

ADIlákÅAòè

Input as a list of characters.

Try it online or verify all test cases.

Explanation:

A          # Push the lowercase alphabet
 D         # Duplicate it
  I        # Push the input character-list
   l       # Convert it to lowercase
    á      # Only keep the letters, removing any other character
     k     # Get the 0-based index of each letter in the alphabet
      ÅA   # Take the average of this list
        ò  # Round it to the nearest integer
         è # 0-based index that into the alphabet
           # (after which the letter is output implicitly as result)

Minor note: it doesn't matter that 05AB1E uses 0-based indexing instead of 1-based as the challenge description, since it just means the entire average is decreased by exactly 1 after taking the average, saving an > after the k and < before the è.

R, 67 63 bytes

Edit: -4 bytes thanks to @jdt.

\(s)intToUtf8(.5+mean(utf8ToInt(gsub("[^a-z]","",tolower(s)))))

Attempt This Online!

Ruby, 69 bytes

->s{t=n=0.0
s.downcase.scan(/[a-z]/){t+=_1.ord;n+=1}
(t/n).round.chr}

Attempt This Online!

Haskell, 104 bytes

f x|l<-[c#64|c<-toEnum.fromEnum<$>x,let n#l=n+sum[32|l<c,c-l<27],0<0#64#96]=toEnum.round$sum l/sum(1<$l)

Surprisingly Double is an instance of Enum.

Try it online!

Perl 5, 47 bytes

sub{@_=map ord,lc(pop)=~/[a-z]/g;chr.5+&sum/@_}

Try it online!

Zsh, 61 bytes

set ${(Ls::)1//[^A-Za-z]};for x;$[t+=#x];jot -c 1 $[t/$#.+.5]

Try it online!

Throws lots of errors because $[t+=#x] should be ((t+=#x)) but that's an extra byte.

JavaScript (Node.js), 75 bytes

s=>(B=Buffer)([s.replace(/[a-z]/gi,c=>t+=B(c)[0&n++]|32,t=n=0)&&t/n+.5])+""

Try it online!

Commented

s =>           // s = input string
(B = Buffer)([ // B = alias for Buffer
  s.replace(   //   replace in s ...
    /[a-z]/gi, //   ... all letters, case insensitive
    c =>       //   for each letter c:
    t += B(c)[ //     add to t the ASCII code of c
      0 & n++  //     and increment n
    ] | 32,    //     force the code to lower case
    t = n = 0  //     start with t = 0 and n = 0
  ) &&         //   end of replace()
  t / n + .5   //   compute the rounded average t / n
])             // end of Buffer()
+ ""           // coerce to a string

Racket, 101 bytes

(λ(s[a(regexp-replace*"[^a-zA-Z]"s"")])(round(/(for/sum([c a])(bitwise-ior 32 c))(bytes-length a))))

Try it online!

Takes input as a byte string and returns an ASCII integer. (Sadly verbose) |32 trick taken from this comment. Rounds .5 to even, which is technically noncompliant, but oh well.

This is my first answer in over two years and my first Racket answer ever, so let me know if there's anything amiss.

Character output (113 bytes):

(λ(s[a(regexp-replace*"[^a-zA-Z]"s"")])(write-byte(round(/(for/sum([c a])(bitwise-ior 32 c)))(bytes-length a))))

Try it online!

Go, 163 137 bytes

import."unicode"
func f(s string)(o rune){for _,r:=range s{if IsLetter(r){o+=r|32-'a'}}
return rune(.5+(float64(o)/float64(len(s))+'a'))}

Attempt This Online!

Factor, 47 bytes

[ >lower 97 ..= 122 within mean round 1string ]

Try it online in an old version of Factor for +1 byte

APL (Dyalog Extended), 24 bytes

(⌊⎕A⊃⍨∘⌊.5++⌿÷≢)27~⍨⎕A⍳⌈

 uppercase

⎕A⍳ one-based indices in uppercase Alphabet (not found → 27)

27~⍨  remove 27s

() apply the following tacit function to that:

   the tally (length)

  ÷ divides

  +⌿ the sum

  .5+ added to one half

  ∘⌊ rounded down, then…

  ⎕A⊃⍨ pick that element from the uppercase Alphabet

   lowercase

Try it online!

Uiua, 16 bytes

+@a⁅÷⧻⟜/+-@A▽⊸±⌵

Try it online!

Explanation

+@a⁅÷⧻⟜/+-@A▽⊸±⌵

               ⌵ # To uppercase
            ▽⊸±  # Keep alphabetic
         -@A     # convert to alphabetic position (A: 0, B: 1, ..)
    ÷⧻⟜/+        # mean
+@a⁅             # round, convert to lowercase letter

C (gcc), 70 bytes

c,t;f(int*s){for(t=c=0;*s;s++)isalpha(*s)?t+=*s|32,c++:0;c=1.*t/c+.5;}

Try it online!

Google Sheets, 82 bytes 102 bytes

=char(0.5+average(sort(code(split(regexreplace(lower(A1),"([a-z])|.","$19"),9)))))

Put the text string in cell A1 and the formula in B1.

Uses sort() as an array enabler only. Signals undefined with 9 and error with #VALUE!.

screenshot

The char() function always rounds down, hence 0.5.

jq -Rr, 70 67 bytes

ascii_downcase|[scan("[a-z]")|explode[]]|add/length|[round]|implode

Demo

JavaScript (Node.js), 78 77 bytes

x=>([...x,w=n=0].map(c=>w+=(d=parseInt(c,36))>9&&++n&&d)|w/n+.5).toString(36)

Try it online!

APL+WIN, 62 bytes

Prompts for string. Fails on domain error if the string does not contain any valid characters.

n[⌊.5+(÷⍴l)×+/l←(((n←⎕av[17+⍳26])⍳s)~27),(⎕av[65+⍳26]⍳s←⎕)~27]

Try it online! Thanks to Dyalog Classic

Python 3, 98 96 95 bytes

lambda s:chr(round(sum(ord(c)-96 for c in s.lower()if c.isalpha())/sum(map(str.isalpha,s)))+96)

Try it online!

Arturo, 68 bytes

$=>[to :char round average to[:integer]to[:char]match lower&{[a-z]}]

Try it!

Retina 0.8.2, 62 bytes

T`Llp`ll_
^(.)\1+$
$1
T`@l`l@`^.
T`l@`@l`.$
}O`.
+r`.(.+).?
$1

Try it online! Link includes test cases. Explanation:

T`Llp`ll_

Lowercase letters and discard anything else.

^(.)\1+$
$1

If all the letters are the same, then just keep one.

T`@l`l@`^.

Increment the first letter.

T`l@`@l`.$

Decrement the last letter.

O`.

Sort the letters (back) into order.

}`

Repeat until the buffer stabilises, which happens either when there is one letter or the buffer only contains copies of two consecutive letters.

+r`.(.+).?
$1

Keep only the middle letter.

Charcoal, 20 bytes

≔Φ↧S№βιθ℅⁺·⁵∕ΣEθ℅ιLθ

Try it online! Link is to verbose version of code. Explanation:

≔Φ↧S№βιθ

Get the letters of the input and lowercase them.

℅⁺·⁵∕ΣEθ℅ιLθ

Take the average, rounded.

Vyxal, 49 bitsv2, 6.125 bytes

ǍøAṁṙøA

Try it Online!

Bitstring:

1101010010111100011000100000010011100010000101010

Very literal implementation of the question.

Explained

ǍøAṁṙøA­⁡​‎‎⁡⁠⁡‏‏​⁡⁠⁡‌⁢​‎‎⁡⁠⁢‏⁠‎⁡⁠⁣‏‏​⁡⁠⁡‌⁣​‎‎⁡⁠⁤‏‏​⁡⁠⁡‌⁤​‎‎⁡⁠⁢⁡‏‏​⁡⁠⁡‌⁢⁡​‎‎⁡⁠⁢⁢‏⁠‎⁡⁠⁢⁣‏‏​⁡⁠⁡‌­
Ǎ        # ‎⁡Remove characters from the input that aren't letters
 øA      # ‎⁢Get the 1-based alphabet index of each letter
   ṁ     # ‎⁣Average those indices
    ṙ    # ‎⁤Round to the nearest integer
     øA  # ‎⁢⁡And convert that back to a letter using the result as a 1-based index
💎

Created with the help of Luminespire.