Ruby - Array.join versus String Concatenation (Efficiency)

后端 未结 5 1793
面向向阳花
面向向阳花 2021-02-05 06:56

I recall getting a scolding for concatenating Strings in Python once upon a time. I was told that it is more efficient to create an List of Strings in Python and join them later

5条回答
  •  失恋的感觉
    2021-02-05 07:10

    Yes, it's the same principle. I remember a ProjectEuler puzzle where I tried it both ways, calling join is much faster.

    If you check out the Ruby source, join is implemented all in C, it's going to be a lot faster than concatenating strings (no intermediate object creation, no garbage collection):

    /*
     *  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("-")   #=> "a-b-c"
     */
    
    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);
    }
    

    where rb_ary_join is:

     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;
    }
    

提交回复
热议问题