programing

루비의 문자열 연결

lastcode 2023. 6. 1. 22:47
반응형

루비의 문자열 연결

루비에서 줄을 연결하는 더 우아한 방법을 찾고 있습니다.

다음과 같은 대사가 있습니다.

source = "#{ROOT_DIR}/" << project << "/App.config"

이것을 하는 더 좋은 방법이 있습니까?

그리고 그 문제와 관련하여, 무엇이 다른가?<<그리고.+?

여러 가지 방법으로 이 작업을 수행할 수 있습니다.

  1. 에서 보여드린 바와 같이<<하지만 그것은 일반적인 방법이 아닙니다.
  2. 문자열 보간 포함

    source = "#{ROOT_DIR}/#{project}/App.config"
    
  3. 와 함께+

    source = "#{ROOT_DIR}/" + project + "/App.config"
    

두 번째 방법은 제가 본 것보다 메모리/속도 측면에서 더 효율적인 것 같습니다(그러나 측정되지는 않았습니다).ROOT_DIR이 0인 경우 세 가지 메서드 모두 초기화되지 않은 상수 오류를 발생시킵니다.

이름을 는 경로이처때리다사수있용다습니할음을름할을다있▁want를 하는 것이 .File.join경로 이름 구분 기호와 혼동하지 않도록 합니다.

결국, 그것은 취향의 문제입니다.

+연산자는 일반적인 연결 선택이며 문자열을 연결하는 가장 빠른 방법일 것입니다.

+그리고.<<은 것은입니다.<<왼쪽에서 개체를 변경합니다.+안 합니다.

irb(main):001:0> s = 'a'
=> "a"
irb(main):002:0> s + 'b'
=> "ab"
irb(main):003:0> s
=> "a"
irb(main):004:0> s << 'b'
=> "ab"
irb(main):005:0> s
=> "ab"

경로만 연결하는 경우 Ruby의 File.join 메서드를 사용할 수 있습니다.

source = File.join(ROOT_DIR, project, 'App.config')

http://greyblake.com/blog/2012/09/02/ruby-perfomance-tricks/ 에서

용사를 합니다.<< 카아concat 효훨입다니보다 훨씬 입니다.+=후자가 시간적 객체를 생성하고 첫 번째 객체를 새 객체로 재정의하기 때문입니다.

require 'benchmark'

N = 1000
BASIC_LENGTH = 10

5.times do |factor|
  length = BASIC_LENGTH * (10 ** factor)
  puts "_" * 60 + "\nLENGTH: #{length}"

  Benchmark.bm(10, '+= VS <<') do |x|
    concat_report = x.report("+=")  do
      str1 = ""
      str2 = "s" * length
      N.times { str1 += str2 }
    end

    modify_report = x.report("<<")  do
      str1 = "s"
      str2 = "s" * length
      N.times { str1 << str2 }
    end

    [concat_report / modify_report]
  end
end

출력:

____________________________________________________________
LENGTH: 10
                 user     system      total        real
+=           0.000000   0.000000   0.000000 (  0.004671)
<<           0.000000   0.000000   0.000000 (  0.000176)
+= VS <<          NaN        NaN        NaN ( 26.508796)
____________________________________________________________
LENGTH: 100
                 user     system      total        real
+=           0.020000   0.000000   0.020000 (  0.022995)
<<           0.000000   0.000000   0.000000 (  0.000226)
+= VS <<          Inf        NaN        NaN (101.845829)
____________________________________________________________
LENGTH: 1000
                 user     system      total        real
+=           0.270000   0.120000   0.390000 (  0.390888)
<<           0.000000   0.000000   0.000000 (  0.001730)
+= VS <<          Inf        Inf        NaN (225.920077)
____________________________________________________________
LENGTH: 10000
                 user     system      total        real
+=           3.660000   1.570000   5.230000 (  5.233861)
<<           0.000000   0.010000   0.010000 (  0.015099)
+= VS <<          Inf 157.000000        NaN (346.629692)
____________________________________________________________
LENGTH: 100000
                 user     system      total        real
+=          31.270000  16.990000  48.260000 ( 48.328511)
<<           0.050000   0.050000   0.100000 (  0.105993)
+= VS <<   625.400000 339.800000        NaN (455.961373)

이 경로를 통해 어레이를 사용하고 참여할 수 있습니다.

source = [ROOT_DIR, project, 'App.config'] * '/'

여기요점에서 영감을 얻은 또 다른 벤치마크가 있습니다.연결을 비교합니다(+(), 추가(()<< ( ) 및간보(보()#{}및 된 문자열에 됩니다.는 동적 및 미리 정의된 문자열입니다.

require 'benchmark'

# we will need the CAPTION and FORMAT constants:
include Benchmark

count = 100_000


puts "Dynamic strings"

Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
  bm.report("concat") { count.times { 11.to_s +  '/' +  12.to_s } }
  bm.report("append") { count.times { 11.to_s << '/' << 12.to_s } }
  bm.report("interp") { count.times { "#{11}/#{12}" } }
end


puts "\nPredefined strings"

s11 = "11"
s12 = "12"
Benchmark.benchmark(CAPTION, 7, FORMAT) do |bm|
  bm.report("concat") { count.times { s11 +  '/' +  s12 } }
  bm.report("append") { count.times { s11 << '/' << s12 } }
  bm.report("interp") { count.times { "#{s11}/#{s12}"   } }
end

출력:

Dynamic strings
              user     system      total        real
concat    0.050000   0.000000   0.050000 (  0.047770)
append    0.040000   0.000000   0.040000 (  0.042724)
interp    0.050000   0.000000   0.050000 (  0.051736)

Predefined strings
              user     system      total        real
concat    0.030000   0.000000   0.030000 (  0.024888)
append    0.020000   0.000000   0.020000 (  0.023373)
interp    3.160000   0.160000   3.320000 (  3.311253)

결론: MRI의 보간은 무겁습니다.

경로 이름을 사용하는 것이 좋습니다.

require 'pathname' # pathname is in stdlib
Pathname(ROOT_DIR) + project + 'App.config'

해서대.<<그리고.+루비 문서에서:

+str에 연결된 other_str을 포함하는 새 문자열을 반환합니다.

<<지정된 개체를 str에 연결합니다.개체가 0에서 255 사이의 수정 번호인 경우 연결 전 문자로 변환됩니다.

첫 피연산자가 .<<제자리에서 변화를 일으킵니다.+새더 . 첫. 그리고 첫 번째 피연산자가 Fixnum(<<그 숫자와 같은 코드를 가진 문자인 것처럼 추가할 것입니다.+error)는 오류를 발생시킵니다.

제 경험을 모두 보여드리겠습니다.

32k개의 레코드를 반환하는 쿼리가 있었습니다. 각 레코드에 대해 데이터베이스 레코드를 형식화된 문자열로 포맷하고 이를 문자열로 연결하는 방법을 호출했습니다. 이 모든 프로세스가 끝나면 디스크의 파일로 변환됩니다.

제 문제는 기록에 따르면 약 24k에 String을 연결하는 과정이 고통스럽게 변했다는 것입니다.

저는 일반적인 '+' 연산자를 사용하여 그것을 하고 있었습니다.

제가 '<<'로 바꾸었을 때는 마법 같았습니다.진짜 빨랐어요.

그래서, 저는 제가 Java를 사용하고 '+'를 사용하여 String을 연결하고 StringBuffer로 변경했던 예전의 1998년의 일을 기억했습니다. (그리고 지금은 Java 개발자가 StringBuilder를 가지고 있습니다.)

루비 월드에서 + / <<의 프로세스는 자바 월드에서 + / StringBuilder.append와 동일하다고 생각합니다.

첫 번째는 메모리의 전체 개체를 재할당하고 다른 하나는 새 주소를 가리키기만 합니다.

연결이라고요?어때.#concat그럼 방법은?

a = 'foo'
a.object_id #=> some number
a.concat 'bar' #=> foobar
a.object_id #=> same as before -- string a remains the same object

공평하게 말하자면,concat에일리어스가 지정됨<<.

이를 위한 추가 방법은 다음과 같습니다.

"String1" + "String2"

"#{String1} #{String2}"

String1<<String2

등등...

사용할 수도 있습니다.%다음과 같이:

source = "#{ROOT_DIR}/%s/App.config" % project

이 접근 방식은 다음과 같이 작동합니다.'따옴표(단일)도 함께 표시합니다.

문자열 정의에서 직접 연결할 수 있습니다.

nombre_apellido = "#{customer['first_name']} #{customer['last_name']} #{order_id}"

사용할 수 있습니다.+또는<<연산자, 그러나 루비로 표시됨.concat함수는 다른 연산자보다 훨씬 빠르기 때문에 가장 선호되는 연산자입니다.이렇게 사용하시면 됩니다.

source = "#{ROOT_DIR}/".concat(project.concat("/App.config"))

상황이 중요합니다. 예를 들어 다음과 같습니다.

# this will not work
output = ''

Users.all.each do |user|
  output + "#{user.email}\n"
end
# the output will be ''
puts output

# this will do the job
output = ''

Users.all.each do |user|
  output << "#{user.email}\n"
end
# will get the desired output
puts output

첫 번째 예제에서는 다음과 연결됩니다.+연산자가 업데이트하지 않습니다.output객체, 그러나 두 번째 예에서,<<운영자가 업데이트합니다.output각 반복이 있는 개체입니다.위와 같은 상황에 대해서는<<더 낫습니다.

당신의 특정한 경우를 위해 당신은 또한 사용할 수 있습니다.Array#join문자열의 파일 경로 유형을 구성할 때:

string = [ROOT_DIR, project, 'App.config'].join('/')]

이는 여러 유형을 문자열로 자동 변환하는 효과가 있습니다.

['foo', :bar, 1].join('/')
=>"foo/bar/1"

Puppet의 경우:

$username = 'lala'
notify { "Hello ${username.capitalize}":
    withpath => false,
}

언급URL : https://stackoverflow.com/questions/377768/string-concatenation-in-ruby

반응형