在一个字符串中查找唯一元素数量的最快方法

6

最佳方式是如何在字符串中找到唯一元素?

示例字符串格式为

myString = "34345667543"

o/p

  ['3','4','3','5'.....]

https://dev59.com/lkvSa4cB1Zd3GeqPivcP - Rasel
6个回答

16

这是一个有趣的问题,由于返回了许多几乎相似的结果,我进行了简单的基准测试来决定哪种解决方案实际上最好:

require 'rubygems'
require 'benchmark'
require 'set'

puts "Do the test"

Benchmark.bm(40) do |x|

  STRING_TEST = "26263636362626218118181111232112233"

  x.report("do split and uniq") do
    (1..1000000).each { STRING_TEST.split(//).uniq }
  end

  x.report("do chars to_a uniq") do
    (1..1000000).each { STRING_TEST.chars.to_a.uniq }
  end

  x.report("using Set") do
    (1..1000000).each { Set.new(STRING_TEST.split('')).to_a }
  end

end

这个测试的结果并不完全令人惊讶(在1.8.7p352上为0n):

                                              user     system      total        real
do split and uniq                        27.060000   0.000000  27.060000 ( 27.084629)
do chars to_a uniq                       14.440000   0.000000  14.440000 ( 14.452377)
using Set                                41.740000   0.000000  41.740000 ( 41.760313)

并且在1.9.2p180版本上:

                                              user     system      total        real
do split and uniq                        19.260000   0.000000  19.260000 ( 19.242727)
do chars to_a uniq                        8.980000   0.010000   8.990000 (  8.983891)
using Set                                28.220000   0.000000  28.220000 ( 28.186787)

REE(1.8.7)的结果接近于1.9.2:

                                              user     system      total        real
do split and uniq                        19.120000   0.000000  19.120000 ( 19.126034)
do chars to_a uniq                       14.740000   0.010000  14.750000 ( 14.766540)
using Set                                32.770000   0.120000  32.890000 ( 32.921878)

出于好玩,我也试了一下 Rubinius:

                                              user     system      total        real
do split and uniq                        26.100000   0.000000  26.100000 ( 26.651468)
do chars to_a uniq                       25.680000   0.000000  25.680000 ( 25.780944)
using Set                                22.500000   0.000000  22.500000 ( 22.649291)

虽然 split('\\').uniq 的可读性更高,但是 chars.to_a.uniq 的速度几乎是它的两倍。

有趣的是,在Rubinius上,Set解决方案是最快的,但在1.9.2上远远不及chars.to_a.uniq


那些时间非常短,可能在误差范围内。尝试将重复次数从400增加到大约400万。 - Andrew Grimm
@andrew 在我的情况下,大约是200万。 - Mohit Jain
1
@andrew: 我更新了基准测试,并且现在我迭代一百万次,再加上我为 Ruby 1.8.7、REE、1.9.2 和 Rubinius 添加了结果(只是为了好玩/教育/兴趣爱好)。 - nathanvda
@nathanvda:谢谢你。有趣的是,Rubinius的结果如此相似。也许他们使用split来处理字符。 - Andrew Grimm

8

使用以下简短代码:

myString.split(//).uniq

6
>> "34345667543".chars.uniq
=> ["3", "4", "5", "6", "7"]

2
#chars(String) 返回一个数组。因此,您可以省略 .to_a,从而得到更简洁的 "34345667543".chars.uniq - stillenat

1
Set.new("34345667543".chars)

我觉得这个表述很好:从字符串中创建一个Set(这意味着唯一的条目)。
这在上面的基准测试中被遗漏了,在我的1.9.3-p274测试中是第二快的(最快的是chars.to_a.uniq)。虽然我们仍然在谈论微基准测试,在应用程序中几乎不可能有影响 :)

1

只需使用split方法:

"12345".split("")

这并没有回答问题。它只是将字符串分割成单个字符,而不是找到唯一的字符。 - Tom De Leu

0
从一个字符串中提取字符并将其制作成一个集合:
irb(main):001:0> require 'set'
irb(main):002:0> Set.new("123444454321".split(''))
=> #<Set: {"1", "2", "3", "4", "5"}>

.split('') 调用只是将字符串按字符拆分成数组。我最初使用了 String#each_char,但那是在1.8.7中新增的功能,而您没有提到您正在使用哪个版本的Ruby。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接