How to efficiently concatenate multiple arrays in Ruby?

前端 未结 3 1222
无人及你
无人及你 2021-01-02 02:56

I just wanted to concatenate multiple arrays in Ruby and couldn\'t find a satisfying way to do so.

Example input:

foo = [1, 2, 3]
ba         


        
3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2021-01-02 03:11

    Did some benchmarks and simple + is the most efficient. So i would suggest to neglect the intermediate creation of an array.

    You could add a new method concat_all to Array like this, but you would have to take into account mixed and multi-dimensional arrays also.

    class Array
      def concat_all 
        self.reduce([], :+)
      end
    end
    [a, b, c].concat_all # a huge array
    [a, b, c].concat_all.length #300000
    

    Here my benchmarks

    require 'Benchmark'
    N = 1000
    
    class Array
      def concat_all 
        self.reduce([], :+)
      end
      def concat_all2
        # just a quick test with fixed numbers for the fill method Stephan proposes but in Ruby itself
        d = Array.new(300_000)
        d[0..99999] = self[0]
        d[100_000..199999] = self[1]
        d[200_000..299999] = self[2]
        d
      end
      def concat_all3
        self.flatten
      end
    end
    
    # small arrays
    a = (1..10).to_a
    b = (11..20).to_a
    c = (21..30).to_a
    
    Benchmark.bm do |r|
      r.report('plus       ')  { N.times { a + b + c }}
      r.report('concat     ') { N.times { [].concat(a).concat(b).concat(c) }}
      r.report('push       ') { N.times { [].push(*a).push(*b).push(*c) }}
      r.report('<<         ') { N.times { ([] << a << b << c).flatten}}
      r.report('splash     ') { N.times {[*a, *b, *c]} }
      r.report('concat_all ')  { N.times { [a, b, c].concat_all }}
      r.report('concat_all3')  { N.times { [a, b, c].concat_all3 }}
      r.report('flat_map   ') { N.times {[a, b, c].flat_map(&:itself)} }
    end
    
    #large arrays
    a = (1..100_000).to_a
    b = (100_001..200_000).to_a
    c = (200_001..300_000).to_a
    
    Benchmark.bm do |r|
      r.report('plus       ')  { N.times { a + b + c }}
      r.report('concat     ') { N.times { [].concat(a).concat(b).concat(c) }}
      r.report('push       ') { N.times { [].push(*a).push(*b).push(*c) }}
      r.report('<<         ') { N.times { ([] << a << b << c).flatten}}
      r.report('splash     ') { N.times {[*a, *b, *c]} }
      r.report('concat_all ')  { N.times { [a, b, c].concat_all }}
      r.report('concat_all2')  { N.times { [a, b, c].concat_all2 }}
      r.report('concat_all3')  { N.times { [a, b, c].concat_all3 }}
      r.report('flat_map   ') { N.times {[a, b, c].flat_map(&:itself)} }
    end
    

    And here the results

    # results for small arrays
           user     system      total        real
    plus         0.000000   0.000000   0.000000 (  0.000416)
    concat       0.000000   0.000000   0.000000 (  0.000592)
    push         0.000000   0.000000   0.000000 (  0.000441)
    <<           0.000000   0.000000   0.000000 (  0.003387)
    splash       0.000000   0.000000   0.000000 (  0.000789)
    concat_all   0.000000   0.000000   0.000000 (  0.001480)
    concat_all3  0.016000   0.000000   0.016000 (  0.003496)
    flat_map     0.000000   0.000000   0.000000 (  0.001036)
    
    # results for big arrays
           user     system      total        real
    plus         0.686000   0.671000   1.357000 (  1.351171)
    concat       0.890000   0.733000   1.623000 (  1.630155)
    push         1.466000   0.624000   2.090000 (  2.092684)
    <<          23.837000   1.045000  24.882000 ( 24.885238)
    splash       1.029000   1.264000   2.293000 (  2.332560)
    concat_all   0.687000   0.967000   1.654000 (  1.709321)
    concat_all2  0.936000   0.780000   1.716000 (  1.730428)
    concat_all3 24.242000   0.998000  25.240000 ( 25.278264)
    flat_map     0.780000   0.765000   1.545000 (  1.551654)
    

提交回复
热议问题