{"slug": "who-has-the-funniest-name", "title": "Who Has the Funniest Name?", "summary": "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'.", "body_md": "During my weekly trivia night (shoutout to our host Ryan), I was\nenlightened with the knowledge that there once lived a man by the name\n[Preserved\nFish](https://en.wikipedia.org/wiki/Preserved_Fish). I of course also recalled the famed mathematician Alexander\nGrothendieck. I endeavoured to find the person with the funniest name. I\nthought that it was definitely possible to write a program to aid me in\nthis search. Apparently, I am the first person to use a programmatic\napproach to solve this problem (at least according to Claude), which\ncomes as a shock to me, since the problem seems very tractable (when set\nup correctly).\n\nAll the code is open-source with an MIT license. You can get it [here](https://github.com/szge/funniest_name) and also find\nPython notebooks to follow along with the subsequent sections. Note that\nyou want several GB of memory available to load the names dataset.\n\n**Associated Python notebook:\npart1.ipynb**\n\nWe begin by defining what it means for a name to sound funny. I\nconsidered an approach involving the pronunciation of names, but this\nseems hard to compute; in addition to computing a pronunciation of a\ngiven name, we’d also have to decipher some sort of meaning from that.\nConsider the classic example name “Hugh Jass” – it’s not immediately\nobvious to me how to write a program to convert this to the phrase “Huge\nAss”. A further consideration is that we’d need to execute this at scale\nacross millions of names1.\n\nIn 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.\n\nGiven this approach, we now need to source two things: a giant list\nof names, and a dictionary (in either case, the bigger the better). For\nour list of names we have a helpful Python package named\n`names-dataset`\n\n, which contains almost 500 million names\nscraped from Facebook. This is the most comprehensive one I could find\navailable to the public. For our dictionary, we will use WordNet2.\n\nThe biggest issue with a naive implementation is that most\ndictionaries/word-corpora available do not include all variants of\nwords. For example, the corpus might include the word “jerk” but may not\ninclude the past participle “jerked”. Therefore, we will use\n`wordnet.synsets()`\n\nto handle this for us by accepting all\nvariants of a word.\n\nFinally, common names like Simon are part of many corpora, which is\nself-defeating for our purposes. It does not make sense to check if a\nname is one of these words. Therefore, we will exclude proper nouns or\n“instances” from our dictionary using\n`any(not syn.instance_hypernyms() for syn in wn.synsets(word))`\n\n.\nThis accepts any word with a non-instance sense, and excludes words\nwhere every sense is an instance. For example, Simon would not be\nconsidered a valid word since all of its senses/definitions under\nWordNet are instances (e.g. “Simon the Apostle”), but Faith is\nacceptable despite being a proper noun since it has a non-instance\nmeaning.\n\nWe’ll finish by decorating our `is_real_word()`\n\nfunction\nwith `@lru_cache`\n\n, which gives us *O*(1) average time complexity for\nlookups and updates. Otherwise, we’d have to check the entire dictionary\nevery time we wanted to know if a word is valid, which increases our\nexecution time to an infeasible amount.\n\nHere is our final code:\n\n``` python\nfrom names_dataset import NameDataset, NameWrapper\nfrom functools import lru_cache\nimport nltk\nfrom nltk.corpus import wordnet as wn\n\nnd = NameDataset()\nfull_names = list(zip(nd.first_names.keys(), nd.last_names.keys()))\n\nfor corpus in [\"wordnet\", \"omw-1.4\"]:\n    try:\n        nltk.data.find(f\"corpora/{corpus}\")\n    except LookupError:\n        nltk.download(corpus)\n\n@lru_cache(maxsize=None)\ndef is_real_word(word):\n    # filter out proper nouns/\"instance\"s (e.g. \"Simon\"); only count non-instance senses as real words.\n    # wn.synsets() already handles standard inflections (\"jerked\" -> \"jerk\").\n    return any(not syn.instance_hypernyms() for syn in wn.synsets(word))\n\nword_names = [name for name in full_names if is_real_word(name[0].lower()) and is_real_word(name[1].lower())]\nprint(\"number of word names:\", len(word_names))\nprint(\"names:\", word_names)\n```\n\nThe result is saved to `names1.txt`\n\n.\n\nNow 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.\n\n**Associated Python notebook:\npart2.ipynb**\n\nThe 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:\n\n``` python\nfrom itertools import combinations\n\nMAX_PARTITIONS = 3\n\ndef get_all_partitions(s):\n    n = len(s)\n    for r in range(min(n, MAX_PARTITIONS)):\n        for cuts in combinations(range(1, n), r):\n            indices = [0, *cuts, n]\n            yield [s[indices[i]:indices[i+1]] for i in range(len(indices) - 1)]\n\ntext = \"abcde\"\nfor partition in get_all_partitions(text):\n    print(partition)\n```\n\nAnd here is the (example) output:\n\n```\n['abcde']\n['a', 'bcde']\n['ab', 'cde']\n['abc', 'de']\n['abcd', 'e']\n['a', 'b', 'cde']\n['a', 'bc', 'de']\n['a', 'bcd', 'e']\n['ab', 'c', 'de']\n['ab', 'cd', 'e']\n['abc', 'd', 'e']\n```\n\nNow, we have many more potential ways for a name to break down into valid words, which should yield a much greater number of results.\n\n**A note on Bell numbers.** Bell numbers count the\nnumber of partitions of a set with size *n*. The sequence of Bell numbers goes\n1, 1, 2, 5, 15, 52, 203, 877, and so on. Bell numbers grow [superexponentially](https://en.wikipedia.org/wiki/Bell_number#Properties),\ni.e. very fast. The average full (first + last) name length in our\ndataset is 15.12 characters, and there are [1382958545](https://oeis.org/A000110) ways to partition a set\nof size 15. Therefore, it is infeasible to check every possible\nrestriction and we are forced to introduce a cap on the number of\npartitions allowed, which I have defined as `MAX_PARTITIONS`\n\n.\nA name which is broken up into a high number of partitions would be\ncomposed of mostly single-letter words, which wouldn’t be very\ninteresting anyways…\n\nWe run the computation and result is saved to\n`names2.txt`\n\n. We now have a list of almost 5000 names, but\nmost of them are not very interesting, such as “Toyo Nashwan”, which is\napparently broken down into valid English words as “toyon ash wan”. A\ntoyon is apparently a type of rose shrub, so while I suppose these are\nvalid words, it’s not really the desired result. I have some ideas for\nhow to improve our search that I will implement in Part 3.\n\n**Associated Python notebook:\npart3.ipynb**\n\nTo 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.\n\nFor parallelization we can use Python’s\n`ProcessPoolExecutor`\n\n. This has some quirks if we want to use\nit in a Jupyter notebook environment (worker processes may not be able\nto locate the correct function), so we will additionally move all of the\nfunctions that need to be called into a separate Python file,\n`word_partition.py`\n\n. The parallelization looks like this:\n\n``` python\n# part3.ipynb\n\nimport os\nfrom concurrent.futures import ProcessPoolExecutor\n\nword_names = []\nwith ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:\n    for result in executor.map(process_full_name, full_names, chunksize=200):\n        if result is not None:\n            word_names.append(result)\n\nprint(word_names[:5])\n\n# word_partition.py\n\ndef process_full_name(full_name):\n    name = full_name[0].lower() + full_name[1].lower()\n    partition = get_valid_word_partitions(name)\n    if partition is None:\n        return None\n    return (*full_name, partition)\n```\n\nIf everything has been set up correctly, we are able to generate our\nnew list of names at this point. The resulting list is about 80000 names\nlong. Here’s a sample name from our new method:\n`Zlota Paswal z lota pa sw al`\n\n(the first two words are the\noriginal full name, and the remaining words are the breakdown into\n“valid English words”). The issue is that most of these words are\nnonsense. They’re words with obscure definitions. Therefore, we’ll add a\nrestriction in our `is_real_word()`\n\nfunction to limit the\ndictionary to the top 10000 most frequent words (according to wordfreq’s\n`top_n_list()`\n\n).\n\nFinally, 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:\n\n```\nWinners:\nBanan Assad (bananas sad)\nHarmat Distance (harm at distance)\nJavahir Evirus (Java hire virus)\nArticles Angelface (articles angel face)\nJapanac Eswar (japan aces war)\nNormalin Konlog (normal ink on log)\n\nRunners-up:\nNotas Konwar (no task on war)\nSwedish Morice (swedish mo rice)\nAsdads Ankle (as dads ankle)\nBasse Atson (bass eat son)\nCentor Bellyman (cent or belly man)\nDogor Buzz (dog or buzz)\nHamad Dicon (ham add icon)\nLate Gunson (late gun son)\nMatter Ingwall (mattering wall)\nZipho Pasian (zip hop asian)\n```\n\n**Disclaimer** This is purely for entertainment. Please\ndo not contact/harass/annoy anyone whose name is mentioned in this\npiece.\n\nWe’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.\n\nI’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.\n\nThere 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.\n\n`/usr/share/dict/words`\n\n(a long list of words available on\nUnix-like systems) as our English dictionary. I soon discovered that I\ncouldn’t naively search if a word belonged in the list since the list\nlacks various modifications like verb tenses (e.g. it contains “jerk”\nbut not “jerked”). Therefore, I had to switch to using the WordNet\ncorpus via nltk which gives us access to more powerful tools.", "url": "https://wpnews.pro/news/who-has-the-funniest-name", "canonical_source": "https://www.jonathanchiang.ca/blog/funniest_names.html", "published_at": "2026-07-30 20:45:55+00:00", "updated_at": "2026-07-30 21:22:37.276230+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Preserved Fish", "Alexander Grothendieck", "Claude", "WordNet", "Facebook", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/who-has-the-funniest-name", "markdown": "https://wpnews.pro/news/who-has-the-funniest-name.md", "text": "https://wpnews.pro/news/who-has-the-funniest-name.txt", "jsonld": "https://wpnews.pro/news/who-has-the-funniest-name.jsonld"}}