如何在Ruby中以相反的顺序高效地处理字符串中的行?

时间:2021-10-04 15:05:45

I am trying to find the most efficient way to process lines in a Ruby string in reverse order. These are the two approaches I have:

我正试图找到一种最有效的方法来以反向顺序处理Ruby字符串中的行。我有两种方法:

def double_reverse(lines)
    lines.reverse!
    lines.each_line do |line|
        line.chomp!
        line.reverse!
        puts line
    end
end

def split_and_reverse(lines)
    lines.split("\n").reverse.each do |line|
        puts line
    end
end

if __FILE__ == $0
    lines = "This is the first line.\nThis is the second line"
    double_reverse(lines)
    lines = "This is the first line.\nThis is the second line"
    split_and_reverse(lines)
end

I am wondering which one will use less memory. Is there any other approach which will use even less resource? I am primarily concerned about memory usage but if I can reduce the CPU usage too that would be nice.

我在想哪个会用更少的内存。有没有其他的方法可以使用更少的资源?我主要关心内存的使用,但是如果我也能减少CPU的使用,那就太好了。

EDIT 1:

编辑1:

In my use case lines can have more than a million lines. If split is going to increase the memory usage by 2x then it is definitely a problem for me. But it may not be a problem if the Ruby VM is smart enough to determine that lines won't be used after the call to split and releases it's memory. On the other hand the in-place reverse! approach theoretically seems to be more efficient since it can be done without making any copy of lines.

在我的用例中,行可以有超过一百万行。如果split将使内存使用量增加2x,那么对我来说肯定是个问题。但是,如果Ruby VM足够聪明,能够在调用split并释放它的内存之后确定不会使用这些行,那么这可能不是问题。另一方面,原地反转!从理论上讲,方法似乎更有效,因为它可以在不产生任何代码副本的情况下完成。

1 个解决方案

#1


6  

Try using Array#reverse_each:

试着用数组# reverse_each:

lines.split("\n").reverse_each do |line|
    puts line
end

Alternatively, if conserving memory is your top priority, then here's a way using String#rindex with which one can be fairly certain is not doing any extra significant memory allocations beyond the original string:

或者,如果保存内存是您的首选项,那么这里有一种方法使用String#rindex,其中一个可以相当确定的是,它不会在原始字符串之外执行任何额外的重要内存分配:

j = lines.length-1 # lines is the full string, not an array

while -1 <= j
  i = lines.rindex("\n", j) || -1
  line = lines[i+1..j]
  puts line
  j = i-1
end

#1


6  

Try using Array#reverse_each:

试着用数组# reverse_each:

lines.split("\n").reverse_each do |line|
    puts line
end

Alternatively, if conserving memory is your top priority, then here's a way using String#rindex with which one can be fairly certain is not doing any extra significant memory allocations beyond the original string:

或者,如果保存内存是您的首选项,那么这里有一种方法使用String#rindex,其中一个可以相当确定的是,它不会在原始字符串之外执行任何额外的重要内存分配:

j = lines.length-1 # lines is the full string, not an array

while -1 <= j
  i = lines.rindex("\n", j) || -1
  line = lines[i+1..j]
  puts line
  j = i-1
end