Write a function or program that, when given a list of names, outputs or returns a list where duplicates of given names have a unique shortened version of their surname.
Input:
A list of names, where a name is defined by a given name and a last name separated by a space. Names are non-empty strings containing only uppercase and lowercase letters. The list can be an array of strings, or the names separated by a constant non-alpha, non-space character, but the output must be in the same format as the input.
Output:
A list of the inputted names in the same order and format as the input that have been modified by these rules:
- For unique given names, output just the given name
- For names that share the same given name:
- As well as their given name, add the shortest unique version of their surname that that is not shared by another name, followed by a period. For instance:
John Clancy, John SmithbecomesJohn C.,John S.andJames Brown, James BrattebecomesJames Bro.,James Bra. - If one surname is a subset of another, such as
Julian King,Julian Kingsley, return the full surname of the smaller one without a period. The example would becomeJulian King,Julian King.
- As well as their given name, add the shortest unique version of their surname that that is not shared by another name, followed by a period. For instance:
- Basically a period represents the regex
.+, where only one name should match it. - You may assume that no-one will share both the same given name and the same surname
- Names are case-sensitive
Test Cases:
John Clancy,Julie Walker,John Walker,Julie Clancy->John C.,Julie W.,John W.,Julie C.Julian King,Jack Johnson,Julian Kingsley>Julian King,Jack,Julian King.Jack Brown,Jack Black,Jack Blue>Jack Br.,Jack Bla.,Jack Blu.John Storm,Jon Snow,Johnny Storm>John,Jon,JohnnyJill DeSoma,Jill Desmond>Jill DeS.,Jill Des.XxXnO sCOppeXxX,XxXNO MERCYXxX>XxXnO,XxXNO
This is code-golf, so the lowest byte count for each language wins.
3 Answers 3
Jelly, (削除) 34 33 32 (削除ここまで) 30 bytes
;\ċÐf6t6ドル;€JṖḊ$$¦".μ€ċ@ÐṂ€Ẏ$Ḣ€
A monadic link taking a list of lists of characters (i.e. a list of "strings") and returning the abbreviations in the same format and relative order.
Try it online! (a full program test suite)
How?
;\ċÐf6t6ドル;€JṖḊ$$¦".μ€ċ@ÐṂ€Ẏ$Ḣ€ - Link: list of lists e.g. ["Sam Ng","Sam Li","Sue Ng"]
μ€ - monadically for €ach: e.g. "Sue Ng"
\ - cumulative reduce with:
; - concatenation ["S","Su","Sue","Sue ","Sue N","Sue Ng"]
6 - literal space character ' '
Ðf - filter keep if:
ċ - count (spaces) ["Sue ","Sue N","Sue Ng"]
6 - literal space character ' '
t€ - trim from €ach ["Sue","Sue N","Sue Ng"]
". - literal period character '.'
¦ - sparse application...
;€ - ...of: concatenate €ach (with a period)
- ...only for these indexes:
$ - last two links as a monad:
J - range of length [1,2,3]
$ - last two links as a monad:
Ṗ - pop [1,2]
Ḋ - dequeue [2] (i.e. 2,3,...,length-1)
- ...i.e.: ["Sue","Sue N.","Sue Ng"]
- yielding: [["Sam","Sam N.","Sam Ng"],["Sam","Sam L.","Sam Li"],["Sue","Sue N.","Sue Ng"]]
$ - last two links as a monad:
Ẏ - tighten ["Sam","Sam N.","Sam Ng","Sam","Sam L.","Sam Li","Sue","Sue N.","Sue Ng"]
ÐṂ€ - filter keep minimals for €ach:
ċ@ - count (sw@ping args) [["Sam N.","Sam Ng"],["Sam L.","Sam Li"],["Sue","Sue N.","Sue Ng"]]
Ḣ€ - head €ach ["Sam N.","Sam L.","Sue"]
Python 2, 130 bytes
def f(a):n=[[x[:i]+'.'*(' 'in x[:i]<x)for i in range(x.find(' '),len(x)+1)]for x in a];print[min(x,key=sum(n,[]).count)for x in n]
First generates all the nicknames, as follows:
n == [
['John', 'John .', 'John C.', 'John Cl.', 'John Cla.', 'John Clan.', 'John Clanc.', 'John Clancy'],
['Julie', 'Julie .', 'Julie W.', 'Julie Wa.', 'Julie Wal.', 'Julie Walk.', 'Julie Walke.', 'Julie Walker'],
['John', 'John .', 'John W.', 'John Wa.', 'John Wal.', 'John Walk.', 'John Walke.', 'John Walker'],
['Julie', 'Julie .', 'Julie C.', 'Julie Cl.', 'Julie Cla.', 'Julie Clan.', 'Julie Clanc.', 'Julie Clancy'],
['Jill', 'Jill .', 'Jill D.', 'Jill De.', 'Jill Des.', 'Jill Desm.', 'Jill Desmo.', 'Jill Desmon.', 'Jill Desmond']
]
Then picks the first* one from each list that is least frequent in sum(n,[]). This will always be the first unique nickname.
Note that n includes the erroneous nicknames 'John .' etc., but they will never be picked.
(*CPython 2.7’s min does so, anyway. This code may not be portable!)
Ruby (削除) 165 162 161 (削除ここまで) 160 bytes
Includes 1 trailing space if only the given name is returned, eg. "John "
->a,n=0,s=0{a.group_by{|i|i[n]}.values.flat_map{|i|j=i[0];k=j.index' ';i.size<2?j.size>n ?j[0,[n+1,k].max-(s>1?0:1)]+(n>k ??.:''):j:f[i,n+=1,i.count{|l|l[n]}]}}
163 bytes if you don't want the trailing space
->a,n=0,s=0{a.group_by{|i|i[n]}.values.flat_map{|i|j=i[0];k=j.index' ';i.size<2?j.size>n ?j[0..[n,k-1].max-(s>1?0:1)]+(n>k ??.: ''):j:f[i,n+1,i.count{|l|l[n+1]}]}}
Angela C.come from the in the test case? \$\endgroup\$Julieoops, thanks. Fixed \$\endgroup\$