Who Has the Funniest Name? A developer created an open-source program to find the person with the funniest name by checking if first and last names are valid English words, using a dataset of nearly 500 million names from Facebook and WordNet for dictionary lookups. The project, available on GitHub with an MIT license, filters out proper nouns like 'Simon' to focus on names composed of real words such as 'Signal Meta'. During my weekly trivia night shoutout to our host Ryan , I was enlightened with the knowledge that there once lived a man by the name Preserved Fish https://en.wikipedia.org/wiki/Preserved Fish . I of course also recalled the famed mathematician Alexander Grothendieck. I endeavoured to find the person with the funniest name. I thought that it was definitely possible to write a program to aid me in this search. Apparently, I am the first person to use a programmatic approach to solve this problem at least according to Claude , which comes as a shock to me, since the problem seems very tractable when set up correctly . All the code is open-source with an MIT license. You can get it here https://github.com/szge/funniest name and also find Python notebooks to follow along with the subsequent sections. Note that you want several GB of memory available to load the names dataset. Associated Python notebook: part1.ipynb We begin by defining what it means for a name to sound funny. I considered an approach involving the pronunciation of names, but this seems hard to compute; in addition to computing a pronunciation of a given name, we’d also have to decipher some sort of meaning from that. Consider the classic example name “Hugh Jass” – it’s not immediately obvious to me how to write a program to convert this to the phrase “Huge Ass”. A further consideration is that we’d need to execute this at scale across millions of names1. In Part 1, we progress by restricting ourselves to names that are composed of real, valid English words e.g. “Signal Meta” . Depending on how big the result is, we can manually filter down to the funny ones, or use programmatic means to do so. Given this approach, we now need to source two things: a giant list of names, and a dictionary in either case, the bigger the better . For our list of names we have a helpful Python package named names-dataset , which contains almost 500 million names scraped from Facebook. This is the most comprehensive one I could find available to the public. For our dictionary, we will use WordNet2. The biggest issue with a naive implementation is that most dictionaries/word-corpora available do not include all variants of words. For example, the corpus might include the word “jerk” but may not include the past participle “jerked”. Therefore, we will use wordnet.synsets to handle this for us by accepting all variants of a word. Finally, common names like Simon are part of many corpora, which is self-defeating for our purposes. It does not make sense to check if a name is one of these words. Therefore, we will exclude proper nouns or “instances” from our dictionary using any not syn.instance hypernyms for syn in wn.synsets word . This accepts any word with a non-instance sense, and excludes words where every sense is an instance. For example, Simon would not be considered a valid word since all of its senses/definitions under WordNet are instances e.g. “Simon the Apostle” , but Faith is acceptable despite being a proper noun since it has a non-instance meaning. We’ll finish by decorating our is real word function with @lru cache , which gives us O 1 average time complexity for lookups and updates. Otherwise, we’d have to check the entire dictionary every time we wanted to know if a word is valid, which increases our execution time to an infeasible amount. Here is our final code: python from names dataset import NameDataset, NameWrapper from functools import lru cache import nltk from nltk.corpus import wordnet as wn nd = NameDataset full names = list zip nd.first names.keys , nd.last names.keys for corpus in "wordnet", "omw-1.4" : try: nltk.data.find f"corpora/{corpus}" except LookupError: nltk.download corpus @lru cache maxsize=None def is real word word : filter out proper nouns/"instance"s e.g. "Simon" ; only count non-instance senses as real words. wn.synsets already handles standard inflections "jerked" - "jerk" . return any not syn.instance hypernyms for syn in wn.synsets word word names = name for name in full names if is real word name 0 .lower and is real word name 1 .lower print "number of word names:", len word names print "names:", word names The result is saved to names1.txt . Now we have a solid framework for finding names, and we have produced a working script that has produced a list of names. Unfortunately, the list is only 188 entries long and for the most part contains uninteresting names. We will remedy this in the following parts. Associated Python notebook: part2.ipynb The main issue with our previous approach is that we are restricting ourselves only to names where the first and last names are each real words. The way I thought of overcoming this is to allow for partitioning, i.e. we will check if parts of names are valid English words as well. To demonstrate what I mean, here is the partitioning code: python from itertools import combinations MAX PARTITIONS = 3 def get all partitions s : n = len s for r in range min n, MAX PARTITIONS : for cuts in combinations range 1, n , r : indices = 0, cuts, n yield s indices i :indices i+1 for i in range len indices - 1 text = "abcde" for partition in get all partitions text : print partition And here is the example output: 'abcde' 'a', 'bcde' 'ab', 'cde' 'abc', 'de' 'abcd', 'e' 'a', 'b', 'cde' 'a', 'bc', 'de' 'a', 'bcd', 'e' 'ab', 'c', 'de' 'ab', 'cd', 'e' 'abc', 'd', 'e' Now, we have many more potential ways for a name to break down into valid words, which should yield a much greater number of results. A note on Bell numbers. Bell numbers count the number of partitions of a set with size n . The sequence of Bell numbers goes 1, 1, 2, 5, 15, 52, 203, 877, and so on. Bell numbers grow superexponentially https://en.wikipedia.org/wiki/Bell number Properties , i.e. very fast. The average full first + last name length in our dataset is 15.12 characters, and there are 1382958545 https://oeis.org/A000110 ways to partition a set of size 15. Therefore, it is infeasible to check every possible restriction and we are forced to introduce a cap on the number of partitions allowed, which I have defined as MAX PARTITIONS . A name which is broken up into a high number of partitions would be composed of mostly single-letter words, which wouldn’t be very interesting anyways… We run the computation and result is saved to names2.txt . We now have a list of almost 5000 names, but most of them are not very interesting, such as “Toyo Nashwan”, which is apparently broken down into valid English words as “toyon ash wan”. A toyon is apparently a type of rose shrub, so while I suppose these are valid words, it’s not really the desired result. I have some ideas for how to improve our search that I will implement in Part 3. Associated Python notebook: part3.ipynb To increase the quality of our results, we need to increase the number of partitions that we search from 3 to 5 . To do this without making the execution time take too long, we introduce parallelization. Parallelization is a natural fit for our purposes since each name can be checked independently and the process has nothing to do with any other name. For parallelization we can use Python’s ProcessPoolExecutor . This has some quirks if we want to use it in a Jupyter notebook environment worker processes may not be able to locate the correct function , so we will additionally move all of the functions that need to be called into a separate Python file, word partition.py . The parallelization looks like this: python part3.ipynb import os from concurrent.futures import ProcessPoolExecutor word names = with ProcessPoolExecutor max workers=os.cpu count as executor: for result in executor.map process full name, full names, chunksize=200 : if result is not None: word names.append result print word names :5 word partition.py def process full name full name : name = full name 0 .lower + full name 1 .lower partition = get valid word partitions name if partition is None: return None return full name, partition If everything has been set up correctly, we are able to generate our new list of names at this point. The resulting list is about 80000 names long. Here’s a sample name from our new method: Zlota Paswal z lota pa sw al the first two words are the original full name, and the remaining words are the breakdown into “valid English words” . The issue is that most of these words are nonsense. They’re words with obscure definitions. Therefore, we’ll add a restriction in our is real word function to limit the dictionary to the top 10000 most frequent words according to wordfreq’s top n list . Finally, we’ve arrived, like Odysseus landing in Ithaca. Our work has produced a reasonably-sized list of 1077 candidate names that we can read through to pick out the funniest ones. After manually picking out my favourite ones, I present to you the people with the funniest names in the world: Winners: Banan Assad bananas sad Harmat Distance harm at distance Javahir Evirus Java hire virus Articles Angelface articles angel face Japanac Eswar japan aces war Normalin Konlog normal ink on log Runners-up: Notas Konwar no task on war Swedish Morice swedish mo rice Asdads Ankle as dads ankle Basse Atson bass eat son Centor Bellyman cent or belly man Dogor Buzz dog or buzz Hamad Dicon ham add icon Late Gunson late gun son Matter Ingwall mattering wall Zipho Pasian zip hop asian Disclaimer This is purely for entertainment. Please do not contact/harass/annoy anyone whose name is mentioned in this piece. We’ve used an iterative process going from proof-of-concept to a proper analysis of finding people with funny names. We’ve used common concepts in programming like caching and parallelization. We’ve demonstrated that an understanding of mathematics and complexity can be helpful in programming. I’m a little disappointed that we don’t have better names Nothing on the final list appears to top Preserved Fish, but at least we have produced something. There are definitely many ways to take this concept further. We could use LLMs. We could match words by sounds instead of spelling. We could use parts-of-speech to produce coherent phrases rather than just considering individual words e.g. adverb-verb or adjective-noun . I’ll leave this for future me or someone else. /usr/share/dict/words a long list of words available on Unix-like systems as our English dictionary. I soon discovered that I couldn’t naively search if a word belonged in the list since the list lacks various modifications like verb tenses e.g. it contains “jerk” but not “jerked” . Therefore, I had to switch to using the WordNet corpus via nltk which gives us access to more powerful tools.