# 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

• May the I/O be lowercase, or is uppercase mandatory? – Kevin Cruijssen Nov 3 '20 at 14:52
• @KevinCruijssen You can do lower case. – Wheat Wizard Nov 3 '20 at 15:38

# 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).)

# 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 – hyper-neutrino 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 – hyper-neutrino Sep 24 '17 at 18:03 • Somehow Mathematica doesn't have a bultin for keyboard rows. – Razetime Sep 19 '20 at 15:25 • @Razetime ah, I see. yeah finding something mathematica doesn't just have a builtin for is always pretty rare :D – hyper-neutrino Sep 19 '20 at 16:54 # 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. ## 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> # 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 # Charcoal, 79 bytes ≔⪪”$±=Ｋ≕⦃Vj@η⟲.w\o:7➙1”¶ηＦθＦ³Ｆ⌕Ａ§ηκι⊞υ⟦λκ⟧ＩＥ²∕ΣＥυ§λιＬθ§§η⁺·⁵∕ΣＥυ⊟ιＬθ⁺·⁵∕ΣＥυ⊟ιＬθ


Try it online!

Neil's golf using string functions.

# Charcoal, 107 bytes

Ｐ”\$±=Ｋ≕⦃Vj@η⟲.w\o:7➙1”≔⟦⟧α≔⟦⟧βＦχ«Ｆ³«ＪικＦθ«¿⁼λＫＫ«⊞α⎇›ⅉ⁰⁺∕¹¦³ⅈⅈ⊞βⅉ»»»»Ｊ⌊∕⁺Σα·⁵Ｌθ⌈∕⁺Σβ·⁵Ｌθ≔ＫＫχ⎚χ¶Ｉ∕ΣαＬθ¶Ｉ∕ΣβＬθ


Try it online!

Draws the keyboard on the canvas and finds the average that way.

# 05AB1E, 44 bytes

žVIšεεžVsδkDZkDŠ3/+à‚]ćøÅAUòDžVsèŠè€θDX.xkè


Not too happy with it, but it works.. :/ Can definitely be golfed some more using a different approach.

I/O in lowercase.

Explanation:

Step 1: create a list with all the coordinate-values, and convert the input in a similar matter as well:

žV                     # Push builtin ["qwertyuiop","asdfghjkl","zxcvbnm"]
Iš                   # Prepend the input-string to this list
ε                  # Map over each string:
ε                 #  Inner map over each individual character:
žV               #   Push ["qwertyuiop","asdfghjkl","zxcvbnm"] again
s              #   Swap so the current character is at the top of the stack
δk            #   Get the index of this character in each of the three strings
#   (or -1 if it's not found)
D           #   Duplicate this list of indices
Z          #   Get the largest index (without popping)
k         #   Get the index of this largest index in the triplet
D        #   Duplicate this index
Š       #   Triple swap the three values on the stack (a,b,c→c,a,b)
3/     #   Divide it by 3
+    #   Add it to each index in the list we duplicated
à   #   Pop and push the maximum again
‚  #   And pair it with the duplicated & triple-swapped index
]                  # Close the nested maps


Try just this first step.

Step 2: get the average coordinate of the input:

ć                      # Extract head; pop and push remainder-list and first item separated
ø                     # Zip/transpose; swapping rows/columns
ÅA                   # Get the arithmetic mean of both inner triplets


Try just the first two steps.

Step 3: get the coordinate closest to this average coordinate, and convert it back to a character to output:

                      # Pop and push both separated to the stack
U                     # Pop and store the second one in variable X
ò                    # Round the first value to the nearest integer
D                   # Duplicate this integer
žV                 # Push ["qwertyuiop","asdfghjkl","zxcvbnm"] yet again
s                # Swap so the integer is at the top of the stack
è               # Index it into the list of strings
Š              # Triple-swap the values on the stack (a,b,c→c,a,b)
è             # Index the duplicated integer into the remainder-list
€θ           # Leave the last value of each inner pair
D          # Duplicate the list
X.x       # Pop the copy and leave the value closest to value X
k      # Get the index of this value in the duplicated list
è     # And index it into the string we triple-swapped
# (after which this character is output implicitly as result)


# Jelly, 33 31 bytes

Æịµ÷3Ċ+
ØQœiⱮÇÆmØQŒṪ¤Çạ¥ÐṂœịØQX


Try it online!

Uses some features that were presumably not implemented when HyperNeutrino wrote his solution, so considering this only beats it by 4 6 bytes, I wouldn't be surprised if a modernized version of his would come out shorter--but I started writing this before I even noticed his existed.

Æịµ÷3Ḟ+                    Helper link (monadic):
Æị                         convert list to complex,
µ   +                    add the complex number to
Ċ                     the imaginary part of
÷3                      its quotient by 3.

ØQœiⱮ                      multidimensional indices of input in QWERTY layout,
Ç                     apply helper link,
Æm                   average;
ØQŒṪ¤              for all multidimensional indices in the layout
ÐṂ         keep those with the smallest
ạ¥           absolute difference between the average and
Ç             their result from the helper link;
œịØQ     index back into QWERTY
X    and choose one key at random.


# 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. – ZaMoC Sep 24 '17 at 18:58