<p>Is there any <strong>simple algorithm</strong> to determine the likeliness of 2 names representing the same person? </p>

<p>I'm not asking for something of the level that Custom department might be using. Just a simple algorithm that would tell me if 'James T. Clark' is most likely the same name as 'J. Thomas Clark' or 'James Clerk'.</p>

<p>If there is an algorithm in <code>C#</code> that would be great, but I can translate from any language.</p>

[{'answer_id': 68422, 'author': 'Antti', 'author_id': 6037, 'author_profile': 'https://Stackoverflow.com/users/6037', 'pm_score': 2, 'selected': False, 'text': '<p><a href="http://en.wikipedia.org/wiki/Levenshtein_distance" rel="nofollow noreferrer">Levenshtein</a> is close, although maybe not exactly what you want.</p>\n'}, {'answer_id': 68437, 'author': 'Sergio Morales', 'author_id': 9506, 'author_profile': 'https://Stackoverflow.com/users/9506', 'pm_score': 0, 'selected': False, 'text': '<p>I doubt there is, considering even the <a href="http://www.upgradetravelbetter.com/2008/09/14/tired-of-secondary-screenings-change-your-name/" rel="nofollow noreferrer">Customs Department doesn\'t seem to have a satisfactory answer</a>...</p>\n'}, {'answer_id': 68452, 'author': 'Lucas Oman', 'author_id': 6726, 'author_profile': 'https://Stackoverflow.com/users/6726', 'pm_score': 0, 'selected': False, 'text': "<p>If there is a solution to this problem I seriously doubt it's a part of core C#. Off the top of my head, it would require a database of first, middle and last name frequencies, as well as account for initials, as in your example. This is fairly complex logic that relies on a database of information.</p>\n"}, {'answer_id': 68466, 'author': 'George Mauer', 'author_id': 5056, 'author_profile': 'https://Stackoverflow.com/users/5056', 'pm_score': 0, 'selected': False, 'text': '<p>Second to Levenshtein distance, what language do you want?  I was able to find an implementation in C# on codeproject pretty easily.</p>\n'}, {'answer_id': 68475, 'author': 'Lee', 'author_id': 6035, 'author_profile': 'https://Stackoverflow.com/users/6035', 'pm_score': 0, 'selected': False, 'text': '<p>In an application I worked on, the Last name field was considered reliable.\nSo presented all the all the records with the same last name to the user.\nUser could sort by the other fields to look for similar names.\nThis solution was good enough to greatly reduce the issue of users creating duplicate records.</p>\n\n<p>Basically looks like the issue will require human judgement.</p>\n'}, {'answer_id': 68511, 'author': 'Andrey Fedorov', 'author_id': 10728, 'author_profile': 'https://Stackoverflow.com/users/10728', 'pm_score': 2, 'selected': False, 'text': '<p>Sounds like you\'re looking for a phonetic-based algorithms, such as <a href="http://en.wikipedia.org/wiki/Soundex" rel="nofollow noreferrer">soundex</a>, <a href="http://en.wikipedia.org/wiki/New_York_State_Identification_and_Intelligence_System" rel="nofollow noreferrer">NYSIIS</a>, or <a href="http://en.wikipedia.org/wiki/Double_Metaphone" rel="nofollow noreferrer">double metaphone</a>. The first actually <em>is</em> what several government departments use, and is trivial to implement (with many implementations readily <a href="http://www.google.com/search?q=soundex+c%23" rel="nofollow noreferrer">available</a>). The second is a slightly more complicated and more precise version of the first. The latter-most works with some non-English names and alphabets.</p>\n\n<p><a href="http://en.wikipedia.org/wiki/Levenshtein_distance" rel="nofollow noreferrer">Levenshtein distance</a> is a definition of distance between two arbitrary strings. It gives you a distance of 0 between identical strings and non-zero between different strings, which might also be useful if you decide to make a custom algorithm.</p>\n'}, {'answer_id': 68570, 'author': 'Stanislav Kniazev', 'author_id': 10757, 'author_profile': 'https://Stackoverflow.com/users/10757', 'pm_score': 3, 'selected': True, 'text': '<p>I\'ve faced similar problem and tried to use Levenstein distance first, but it did not work well for me. I came up with an algorithm that gives you "similarity" value between two strings (higher value means more similar strings, "1" for identical strings). This value is not very meaningful by itself (if not "1", always 0.5 or less), but works quite well when you throw in Hungarian Matrix to find matching pairs from two lists of strings.</p>\n\n<p>Use like this:</p>\n\n<pre><code>PartialStringComparer cmp = new PartialStringComparer();\ntbResult.Text = cmp.Compare(textBox1.Text, textBox2.Text).ToString();\n</code></pre>\n\n<p>The code behind:</p>\n\n<pre><code>public class SubstringRange {\n    string masterString;\n\n    public string MasterString {\n        get { return masterString; }\n        set { masterString = value; }\n    }\n    int start;\n\n    public int Start {\n        get { return start; }\n        set { start = value; }\n    }\n    int end;\n\n    public int End {\n        get { return end; }\n        set { end = value; }\n    }\n    public int Length {\n        get { return End - Start; }\n        set { End = Start + value;}\n    }\n\n    public bool IsValid {\n        get { return MasterString.Length &gt;= End &amp;&amp; End &gt;= Start &amp;&amp; Start &gt;= 0; }\n    }\n\n    public string Contents {\n        get {\n            if(IsValid) {\n                return MasterString.Substring(Start, Length);\n            } else {\n                return "";\n            }\n        }\n    }\n    public bool OverlapsRange(SubstringRange range) {\n        return !(End &lt; range.Start || Start &gt; range.End);\n    }\n    public bool ContainsRange(SubstringRange range) {\n        return range.Start &gt;= Start &amp;&amp; range.End &lt;= End;\n    }\n    public bool ExpandTo(string newContents) {\n        if(MasterString.Substring(Start).StartsWith(newContents, StringComparison.InvariantCultureIgnoreCase) &amp;&amp; newContents.Length &gt; Length) {\n            Length = newContents.Length;\n            return true;\n        } else {\n            return false;\n        }\n    }\n}\n\npublic class SubstringRangeList: List&lt;SubstringRange&gt; {\n    string masterString;\n\n    public string MasterString {\n        get { return masterString; }\n        set { masterString = value; }\n    }\n\n    public SubstringRangeList(string masterString) {\n        this.MasterString = masterString;\n    }\n\n    public SubstringRange FindString(string s){\n        foreach(SubstringRange r in this){\n            if(r.Contents.Equals(s, StringComparison.InvariantCultureIgnoreCase))\n                return r;\n        }\n        return null;\n    }\n\n    public SubstringRange FindSubstring(string s){\n        foreach(SubstringRange r in this){\n            if(r.Contents.StartsWith(s, StringComparison.InvariantCultureIgnoreCase))\n                return r;\n        }\n        return null;\n    }\n\n    public bool ContainsRange(SubstringRange range) {\n        foreach(SubstringRange r in this) {\n            if(r.ContainsRange(range))\n                return true;\n        }\n        return false;\n    }\n\n    public bool AddSubstring(string substring) {\n        bool result = false;\n        foreach(SubstringRange r in this) {\n            if(r.ExpandTo(substring)) {\n                result = true;\n            }\n        }\n        if(FindSubstring(substring) == null) {\n            bool patternfound = true;\n            int start = 0;\n            while(patternfound){\n                patternfound = false;\n                start = MasterString.IndexOf(substring, start, StringComparison.InvariantCultureIgnoreCase);\n                patternfound = start != -1;\n                if(patternfound) {\n                    SubstringRange r = new SubstringRange();\n                    r.MasterString = this.MasterString;\n                    r.Start = start++;\n                    r.Length = substring.Length;\n                    if(!ContainsRange(r)) {\n                        this.Add(r);\n                        result = true;\n                    }\n                }\n            }\n        }\n        return result;\n    }\n\n    private static bool SubstringRangeMoreThanOneChar(SubstringRange range) {\n        return range.Length &gt; 1;\n    }\n\n    public float Weight {\n        get {\n            if(MasterString.Length == 0 || Count == 0)\n                return 0;\n            float numerator = 0;\n            int denominator = 0;\n            foreach(SubstringRange r in this.FindAll(SubstringRangeMoreThanOneChar)) {\n                numerator += r.Length;\n                denominator++;\n            }\n            if(denominator == 0)\n                return 0;\n            return numerator / denominator / MasterString.Length;\n        }\n    }\n\n    public void RemoveOverlappingRanges() {\n        SubstringRangeList l = new SubstringRangeList(this.MasterString);\n        l.AddRange(this);//create a copy of this list\n        foreach(SubstringRange r in l) {\n            if(this.Contains(r) &amp;&amp; this.ContainsRange(r)) {\n                Remove(r);//try to remove the range\n                if(!ContainsRange(r)) {//see if the list still contains "superset" of this range\n                    Add(r);//if not, add it back\n                }\n            }\n        }\n    }\n\n    public void AddStringToCompare(string s) {\n        for(int start = 0; start &lt; s.Length; start++) {\n            for(int len = 1; start + len &lt;= s.Length; len++) {\n                string part = s.Substring(start, len);\n                if(!AddSubstring(part))\n                    break;\n            }\n        }\n        RemoveOverlappingRanges();\n    }\n}\n\npublic class PartialStringComparer {\n    public float Compare(string s1, string s2) {\n        SubstringRangeList srl1 = new SubstringRangeList(s1);\n        srl1.AddStringToCompare(s2);\n        SubstringRangeList srl2 = new SubstringRangeList(s2);\n        srl2.AddStringToCompare(s1);\n        return (srl1.Weight + srl2.Weight) / 2;\n    }\n}\n</code></pre>\n\n<p>Levenstein distance one is much simpler (adapted from <a href="http://www.merriampark.com/ld.htm" rel="nofollow noreferrer">http://www.merriampark.com/ld.htm</a>):</p>\n\n<pre><code>public class Distance {\n    /// &lt;summary&gt;\n    /// Compute Levenshtein distance\n    /// &lt;/summary&gt;\n    /// &lt;param name="s"&gt;String 1&lt;/param&gt;\n    /// &lt;param name="t"&gt;String 2&lt;/param&gt;\n    /// &lt;returns&gt;Distance between the two strings.\n    /// The larger the number, the bigger the difference.\n    /// &lt;/returns&gt;\n    public static int LD(string s, string t) {\n        int n = s.Length; //length of s\n        int m = t.Length; //length of t\n        int[,] d = new int[n + 1, m + 1]; // matrix\n        int cost; // cost\n        // Step 1\n        if(n == 0) return m;\n        if(m == 0) return n;\n        // Step 2\n        for(int i = 0; i &lt;= n; d[i, 0] = i++) ;\n        for(int j = 0; j &lt;= m; d[0, j] = j++) ;\n        // Step 3\n        for(int i = 1; i &lt;= n; i++) {\n            //Step 4\n            for(int j = 1; j &lt;= m; j++) {\n                // Step 5\n                cost = (t.Substring(j - 1, 1) == s.Substring(i - 1, 1) ? 0 : 1);\n                // Step 6\n                d[i, j] = System.Math.Min(System.Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost);\n            }\n        }\n        // Step 7\n        return d[n, m];\n    }\n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/68408', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3610/']