如何优雅地计算ruby中单词的anagram签名?

出于这个问题,我正在寻找一种优雅(ruby)的方式来计算这个答案中建议的单词签名。

建议的想法是对单词中的字母进行排序,并运行长度编码重复的字母。 因此,例如“mississippi”首先变成“iiiimppssss”,然后可以通过编码为“4impp4s”进一步缩短。

我对ruby相对较新,虽然我可以一起破解,但我确信这对于有ruby经验的人来说是一个单线。 我有兴趣看到人们的方法,并提高我的ruby知识。

编辑:澄清一下,计算签名的性能对我的应用程序来说并不重要。 我正在寻找计算签名所以我可以将它与每个单词存储在一个大的单词数据库(450K单词)中,然后查询具有相同签名的单词(即给定单词的所有字谜,即实际英语单词) )。 因此关注空间。 “优雅”部分只是为了满足我的好奇心。

我也不是一个Ruby人,但正如我在其他评论中所指出的,这似乎适用于所描述的算法。

s = "mississippi" s.split('').sort.join.gsub(/(.)\1{2,}/) { |s| s.length.to_s + s[0,1] } 

当然,您需要确保单词为小写,不包含数字等。

根据要求,我将尝试解释代码。 如果我没有得到所有的Ruby或reg ex术语,请原谅我。

我认为分割/排序/连接部分非常简单。 对我来说有趣的部分始于对gsub的调用。 这将替换与正则表达式匹配的子字符串以及其后面的块的返回值。 reg ex找到任何字符并创建反向引用。 那就是“(。)”部分。 然后,我们使用反向引用“\ 1”继续匹配过程,该反向引用评估匹配的第一部分找到的任何字符。 我们希望找到该字符至少两次,总的最小出现次数为3次。 这是使用量词“{2,}”完成的。

如果找到匹配项,则匹配的子字符串将作为参数传递给下一个代码块,这要归功于“| s |” 部分。 最后,我们使用匹配子字符串长度的字符串等效字符并将其附加到该字符串组成的任何字符(它们应该都相同)并返回连接值。 返回的值将替换原始匹配的子字符串。 整个过程一直持续到没有任何东西要匹配,因为它是原始字符串的全局替换。

如果那令人困惑,我道歉。 通常情况下,我更容易想象解决方案而不是清楚地解释它。

创建字母排序列表的最快方法是:

 "mississippi".unpack("c*").sort.pack("c*") 

它比split(”)和join()快得多。 为了进行比较,最好将数组一起打包成一个String,这样你就不必比较数组了。

我没有看到优雅的解决方案。 您可以使用split消息将字符转换为数组,但是一旦您对列表进行了排序,我就没有看到一个很好的线性时间连接原语来返回字符串。 我很惊讶。

顺便说一句, 游程编码几乎肯定是浪费时间 。 在我认为值得考虑之前,我必须看到一些非常令人印象深刻的测量结果。 如果您避免使用行程编码,则可以对任何字符串进行字形化 ,而不仅仅是字符串。 如果你知道你只有字母并试图节省空间,你可以将它们打包5个字母。

— Irma Vep


编辑 :另一张海报发现我错过了join 。 尼斯。