# Find the average of a word

Inspired by this chat message

Your task will be to take a word and find the average position of its letters on the keyboard as a letter.

## Keyboard Layout

Since layouts vary from keyboard to keyboard, we will be using a standard based of of my own keyboard in this question.

The keyboard has 3 rows, the top row from left to right contains the keys

QWERTYUIOP


The second row contains the letters

ASDFGHJKL


The final row contains

ZXCVBNM


Each letter is 1 unit horizontal from its neighbor to the left. This means that W is 1 away from Q and E is 1 away from W and so on.

The keys at the beginning of each row have the positions:

Q : 0,0
A : 1/3,1
Z : 2/3,2


This means that the rows are separated one unit vertically and the bottom two rows are shifted by a third from the row above them.

You should take a word as input and output the letter that is closest to the average position of the letters in its word. The average of a set of vectors is

(average x value, average y value)


When two keys are equidistant from the average you may output either as the "closest" key.

This is so answers will be scored in bytes with fewer bytes being better.

## Example solution

Let's calculate the average of APL.

We convert each letter to a vector

A -> (1/3,1)
P -> (9,0)
L -> (8 1/3,1)


We add these up the three vectors to get (17 2/3, 2). We then divide each coordinate by 3 (The number of letters in the word) to get (5 8/9, 2/3).

The closest letter to (5 8/9, 2/3) is J at (6 1/3,1) so our result is J.

## Test Cases

APL  -> J
TEXT -> R
PPCG -> J
QQQQ -> Q
ZZZZ -> Z
PPPP -> P
MMMM -> M
QQSS -> A or W


# C# (.NET Core), 250 + 13 bytes

+13 bytes for using System;

n=>{var a=new[]{"QWERTYUIOP","ASDFGHJKL","ZXCVBNM"};float x=0,y=0;int i=0,j=0,l=n.Length;foreach(char c in n){for(i=0,j=0;i<2;){if(a[i][j]==c)break;if(++j>=a[i].Length){i++;j=0;}}x+=j;y+=i;}return a[(int)Math.Round(y/3)][(int)Math.Round(x/l+y/l/3)];}


Try it online!

Little sidenote: This outputs F for TEXT, since that was the original desired output.
Outputting R instead of F was changed after this answer was posted.

# Jelly, 37 bytes

ØQi€µT÷3Ḣ+Ṁ;T
Ç€ZÆmðạ²SðÐ€ØAÇ€¤iṂ$ịØA  Try it online! lol way too long # Explanation ØQi€µT÷3Ḣ+Ṁ;T Helper Link; compute the position of a key € For each row of ØQ ["QWERTYUIOP", "ASDFGHJKL", "ZXCVBNM"] (hooray for builtins) i Find the first occurrence of the argument µ Start a new monadic chain T List of indices of truthy values; singleton list with the row of the key ÷ Divide the index by 3 3 Ḣ Take the first element + Add it to the original list Ṁ Take the maximum (the adjusted horizontal position of the key) ; Append T The index of the truthy value (the row) Ç€ZÆmðạ²SðÐ€ØAÇ€¤iṂ$ịØA  Main Link
€                       For each character in the input
Ç                        Compute its position using the helper link
Z                      Zip (all of the horizontal positions are in the first list; all of the vertical positions are in the second list)
Æm                    Take the arithmetic mean (of each sublist)
ðạ²Sð               Dyadic chain to compute the distance (squared) between two coordinates
ạ                  Take the absolute difference between each coordinate value (auto-vectorization)
²                 Square each value
S                Take the sum (returns the distance squared but for comparison that's fine)
Ð€             Take the distance between the mean position and each element in
ØAÇ€¤        [Nilad:] the positions of each character in the uppercase alphabet
€         For each character in
ØA           "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Ç          Compute its position
iṂ$Find the index of the minimum (closest) i First occurrence of in the list of distances Ṃ the minimum ị Index back into ØA The alphabet  • @downvoter the issue with the test case has been fixed; please remove your downvote or explain why you wish to downvote my answer – HyperNeutrino Sep 24 '17 at 17:41 • I think it disagrees again? F doesn't seem to be an allowed output anymore... – Erik the Outgolfer Sep 24 '17 at 18:02 • @EriktheOutgolfer Ah okay I didn't update that remark after FCM corrected the test case – HyperNeutrino Sep 24 '17 at 18:03 • Somehow Mathematica doesn't have a bultin for keyboard rows. – Razetime Sep 19 at 15:25 • @Razetime ah, I see. yeah finding something mathematica doesn't just have a builtin for is always pretty rare :D – HyperNeutrino Sep 19 at 16:54 ## JavaScript (ES6), 166 bytes f= s=>[...s].map(c=>(h+=c=s.search(c),v+=c%3,l++),h=v=l=0,s='QAZWSXEDCRFVTGBYHNUJMIKKOLLP')&&[...s].map((c,i)=>(i=(i-h/l)*(i-h/l)+(i=i%3-v/l)*i*9,i)<m&&(m=i,r=c),m=9)&&r <input oninput=o.textContent=/^[A-Z]+$/.test(this.value)?f(this.value):><pre id=o>

6 bytes could be saved by switching to ES7. Previous 131-byte solution used a simplistic distance check which is no longer acceptable.

f=
s=>([...s].map(c=>(h+=c=s.search(c),v+=c%3,l++),h=v=l=0,s='QAZWSXEDCRFVTGBYHNUJMIKKOLLP'),v=(v/l+.5|0),h=((h/l-v)/3+.5|0),s[h*3+v])
<input oninput=o.textContent=/^[A-Z]+\$/.test(this.value)?f(this.value):><pre id=o>

# Python 3, 130 bytes

lambda w,d={'QAZWSXEDCRFVTGBYHNUJMIKOOLPP'[i]:i%3*1j+i/3for i in range(28)}:min(d,key=lambda c:abs(d[c]-sum(map(d.get,w))/len(w)))


Try it online!

d={'QAZWSXEDCRFVTGBYHNUJMIKOOLPP'[i]:i%3*1j+i/3for i in range(28)} constructs the mapping from letters to points (represented as complex numbers, (x+y*1j)).

As for the lambda body, sum(map(d.get,w))/len(w) computes the average position of word w, and putting that in min(d,key=lambda c:abs(d[c]-…)) finds the closest letter to that position. (For complex numbers, abs(A-B) corresponds to the Euclidean distance between (A.real, A.imag) and (B.real, B.imag).)

# Java, 257 243 242 237 bytes

char h(String s){int l=s.length(),i=l+28;s="QAZWSXEDCRFVTGBYHNUJMIK<OL>P"+s;float d=9,x=0,y=0,e;for(;i>28;y+=(e=s.indexOf(s.charAt(--i)))%3/l,x+=e/3/l);for(;i-->0;)if((e=(x-i/3f)*(x-i/3f)+(y-i%3)*(y-i%3))<d){d=e;l=i;}return s.charAt(l);}


Saved 14 bytes - the distance away from the best key will be less than 3 units

# Java (OpenJDK 8), 452431424400389324322296285281276274260258 257 bytes

Something to start golfing from

s->{String c="QWERTYUIOPASDFGHJKL;ZXCVBNM";int i=0,r=0,l=0;double x=0,y=0,D=99,t,f=s.length();for(;i<f;x+=l%10+l/10/3d,y+=l/10)l=c.indexOf(s.charAt(i++));for(;r<27;r++)if(D>(t=Math.pow(x/f-r/10/3d-r%10,2)+Math.pow(y/f-r/10,2))){D=t;l=r;}return c.charAt(l);}


Try it online!

• Gives me the wrong result for TEXT. – Ian H. Sep 24 '17 at 17:36
• @IanH. It gives me 'R' which is what OP asked for – Roberto Graham Sep 24 '17 at 17:39
• Didn't see that was changed in the task, my bad. – Ian H. Sep 24 '17 at 17:41
• – Jonathan Frech Sep 24 '17 at 17:47
• I hadn't seen this answer when I posted mine, should I have suggested mine as a comment or are multiple answers for the same language ok? – Tahg Sep 24 '17 at 21:18

# Mathematica, 234 bytes

(r=(K=Round)@Mean[If[(w=First[q=#&@@Position[(s=X/@{"QWERTYUIOP","ASDFGHJKL","ZXCVBNM"}),#]])==1,q=q-1,If[w==2,q=q+{-1,-2/3},q=q+{-1,-1/3}]]&/@(X=Characters)@#];z=If[(h=#&@@r)==0,r=r+1,If[h==1,r=r+{1,2/3},r=r+{1,1/3}]];s[[##]]&@@K@z)&

• Fixed! works for all test cases. – J42161217 Sep 24 '17 at 18:58