Ruby – Array.join与字符串连接(效率)

我记得曾经因为在Python中连接字符串而受到责骂。 有人告诉我,在Python中创建一个字符串列表并在以后加入它们会更有效。 我把这种做法带到了JavaScript和Ruby中,虽然我不确定它在后者中是否具有相同的好处。

任何人都可以告诉我,加入一个字符串数组并调用它是否更有效(资源和执行):加入它们或者根据需要在Ruby编程语言中连接一个字符串?

谢谢。

使用Benchmark类自己尝试一下。

require "benchmark" n = 1000000 Benchmark.bmbm do |x| x.report("concatenation") do foo = "" n.times do foo << "foobar" end end x.report("using lists") do foo = [] n.times do foo << "foobar" end string = foo.join end end 

这会产生以下输出:

 Rehearsal ------------------------------------------------- concatenation 0.300000 0.010000 0.310000 ( 0.317457) using lists 0.380000 0.050000 0.430000 ( 0.442691) ---------------------------------------- total: 0.740000sec user system total real concatenation 0.260000 0.010000 0.270000 ( 0.309520) using lists 0.310000 0.020000 0.330000 ( 0.363102) 

因此,在这种情况下,连接似乎更快一些。 根据您的用例对您的系统进行基准测试。

有趣,基准测试给出了惊人的结果(除非我做错了):

 require 'benchmark' N = 1_000_000 Benchmark.bm(20) do |rep| rep.report('+') do N.times do res = 'foo' + 'bar' + 'baz' end end rep.report('join') do N.times do res = ['foo', 'bar', 'baz'].join end end rep.report('<<') do N.times do res = 'foo' << 'bar' << 'baz' end end end 

 jablan@poneti:~/dev/rb$ ruby concat.rb user system total real + 1.760000 0.000000 1.760000 ( 1.791334) join 2.410000 0.000000 2.410000 ( 2.412974) << 1.380000 0.000000 1.380000 ( 1.376663) 

join原来是最慢的。 它可能与创建数组有关,但这就是你必须要做的事情。

哦BTW,

 jablan@poneti:~/dev/rb$ ruby -v ruby 1.9.1p378 (2010-01-10 revision 26273) [i486-linux] 

是的,这是相同的原则。 我记得一个ProjectEuler拼图,我在那里尝试了两种方式,调用join更快。

如果你查看了Ruby源代码,那么连接是用C语言实现的,它会比连接字符串快得多(没有中间对象创建,没有垃圾回收):

 /* * call-seq: * array.join(sep=$,) -> str * * Returns a string created by converting each element of the array to * a string, separated by sep. * * [ "a", "b", "c" ].join #=> "abc" * [ "a", "b", "c" ].join("-") #=> "abc" */ static VALUE rb_ary_join_m(argc, argv, ary) int argc; VALUE *argv; VALUE ary; { VALUE sep; rb_scan_args(argc, argv, "01", &sep); if (NIL_P(sep)) sep = rb_output_fs; return rb_ary_join(ary, sep); } 

其中rb_ary_join是:

  VALUE rb_ary_join(ary, sep) VALUE ary, sep; { long len = 1, i; int taint = Qfalse; VALUE result, tmp; if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue; for (i=0; ilen; i++) { tmp = rb_check_string_type(RARRAY(ary)->ptr[i]); len += NIL_P(tmp) ? 10 : RSTRING(tmp)->len; } if (!NIL_P(sep)) { StringValue(sep); len += RSTRING(sep)->len * (RARRAY(ary)->len - 1); } result = rb_str_buf_new(len); for (i=0; ilen; i++) { tmp = RARRAY(ary)->ptr[i]; switch (TYPE(tmp)) { case T_STRING: break; case T_ARRAY: if (tmp == ary || rb_inspecting_p(tmp)) { tmp = rb_str_new2("[...]"); } else { VALUE args[2]; args[0] = tmp; args[1] = sep; tmp = rb_protect_inspect(inspect_join, ary, (VALUE)args); } break; default: tmp = rb_obj_as_string(tmp); } if (i > 0 && !NIL_P(sep)) rb_str_buf_append(result, sep); rb_str_buf_append(result, tmp); if (OBJ_TAINTED(tmp)) taint = Qtrue; } if (taint) OBJ_TAINT(result); return result; } 

我刚刚读到这个。 Attahced是一个谈论它的链接。

-建设一个字符串,从零配件

据我所知,在Python和Java字符串中,不可变对象与数组不同,而在Ruby中,字符串和数组彼此可变。 使用String.concat或<<方法形成字符串与Array.join之间的速度可能存在最小差异,但它似乎不是一个大问题。

我认为链接会比我更好地解释这个。

谢谢,

马丁

“问题在于整个数据堆。在他的第一种情况下,他有两种类型的数据存储:(1)CSV文件中每行的临时字符串,固定引用等等,以及(2)包含所有内容的巨型字符串。如果每个字符串是1k并且有5,000行……

场景一:用小字符串构建一个大字符串

临时字符串:5兆(5,000k)大量字符串:5兆(5,000k)总计:10兆(10,000k)Dave的改进脚本将大量字符串换成arrays。 他保留了临时字符串,但将它们存储在一个数组中。 该数组最终将耗费5000 * sizeof(VALUE)而不是每个字符串的完整大小。 通常,VALUE是四个字节。

场景二:将字符串存储在数组中

字符串:5兆(5,000k)大规模arrays:20k

然后,当我们需要制作一个大字符串时,我们称之为join。 现在我们达到了10兆,突然所有这些字符串成为临时字符串,它们都可以立即释放。 最终这是一个巨大的成本,但它比一直消耗资源的逐渐渐强更有效率。 “

http://viewsourcecode.org/why/hacking/theFullyUpturnedBin.html

^在内存/垃圾收集性能方面实际上更好的是将操作延迟到最后,就像我在Python中教过的那样。 之所以开始,你会在最后获得一大块分配并立即释放对象。