Объяснение фрагмента кода Ruby - PullRequest
4 голосов
/ 08 января 2011

Я снова в том неудобном положении, когда кто-то оставил мне фрагмент кода на языке, которого я не знаю, и я должен его поддерживать.Хотя я не представлял себе Ruby, некоторые его части довольно просты, но я все же хотел бы услышать ваши объяснения.Вот так:

words = File.open("lengths.txt") {|f| f.read }.split # read all lines of a file in 'words'?

values = Array.new(0)
words.each { |value| values << value.to_i } # looked this one up, it's supposed to convert to an array of integers, right?
values.sort!
values.uniq!

diffs = Array.new(0) # this looks unused, unless I'm missing something obvious
sum = 0
s = 0 # another unused variable
# this looks like it's computing the sum of differences between successive
# elements, but that sum also remains unused, or does it?
values.each_index { |index| if index.to_i < values.length-1 then sum += values.at(index.to_i + 1) - values.at(index.to_i) end } # could you also explain the syntax here?
puts "delta has the value of\n"

# this will eventually print the minimum of the original values divided by 2
puts values.at(0) / 2

Приведенный выше скрипт должен был вычислить среднее значение различий между каждыми двумя последовательными элементами (по существу, целыми числами) в списке.Прав ли я, говоря, что это далеко не так, как на самом деле, или я упускаю что-то фундаментальное, что, вероятно, предполагает, что у меня нет знаний по Ruby?

Ответы [ 3 ]

9 голосов
/ 08 января 2011

Объяснение + рефакторинг (неиспользованные переменные удалены, функциональный подход, each_cons):

# Read integer numbers from file, sort them ASC and remove duplicates
values = File.read("lengths.txt").split.map(&:to_i).sort.uniq

# Take pairwise combinations and get the total sum of partial differences
partial_diffs = values.each_cons(2).map { |a, b| b - a }.inject(0, :+)
7 голосов
/ 08 января 2011

Этот парень, конечно, не схватил Руби сам. Интересно, почему он решил использовать этот язык?

Вот аннотированное объяснение:

# Yes, it reads all lines of a file in words (an array)
words = File.open("lengths.txt") {|f| f.read }.split

values = Array.new(0)
# Yes, to_i convert string into integer
words.each { |value| values << value.to_i }
values.sort!
values.uniq!

# diffs and s seem unused
diffs = Array.new(0)
sum = 0
s = 0

# The immediate line below can be read as `for(int index = 0; index < values.length; index++)`
values.each_index { |index|
    # index is integer, to_i is unnecessary
    if index.to_i < values.length-1 then

        # The `sum` variable is used here
        # Following can be rewritten as sum += values[i-1] - values[i]
        sum += values.at(index.to_i + 1) - values.at(index.to_i)
    end
}

puts "delta has the value of\n"

# Yes, this will eventually print the minimal of the original values divided by 2
puts values.at(0) / 2

Чтобы помочь вам лучше понять, как выглядит "настоящий" (идиоматический) Ruby, я написал то, что вы хотели, с некоторыми аннотациями

values = open("lengths.txt") do |f|
    # Read it like this:
    #
    # Take the list of all lines in a file,
    # apply a function to each line
    # The function is stripping the line and turning it 
    # into an integer
    # (This means the resultant list is a list of integers)
    #
    # And then sort it and unique the resultant list
    #
    # The eventual resultant list is assigned to `values`
    # by being the return value of this "block"
    f.lines.map { |l| l.strip.to_i }.sort.uniq
end

# Assign `diffs` to an empty array (instead of using Array.new())
diffs = []
values.each_index do |i|
    # Syntactic sugar for `if`
    # It applies the 1st part if the 2nd part is true
    diffs << (values[i+1] - values[i]) if i < values.length - 1
end

# You can almost read it like this:
#
# Take the list `diffs`, put all the elements in a sentence, like this 
# 10 20 30 40 50
#
# We want to inject the function `plus` in between every element, 
# so it becomes
# 10 + 20 + 30 + 40 + 50
#
# The colon `:+` is used to refer to the function `plus` as a symbol
#
# Take the result of the above summation, divided by length,
# which gives us average
delta = diffs.inject(:+) / diffs.length

# `delta` should now contains the "average of differences" between 
# the original `values`

# String formatting using the % operator
# No \n needed since `puts` already add one for us
puts "delta has the value of %d" % delta

Это никоим образом не продвигает истинную силу Ruby, но вы понимаете, почему Rubyists так увлекаются выразительностью и прочим: P

1 голос
/ 08 января 2011
values.each_index { |index| if index.to_i < values.length-1 then sum += values.at(index.to_i + 1) - values.at(index.to_i) end } 

Приведенная выше строка суммирует различия между последовательными значениями. тест index.to_i < values.length-1 состоит в том, чтобы не получить доступ к массиву вне границ из-за values.at(index.to_i + 1).

Вы правы, этот код ничего не делает. он печатает только половину минимального значения из файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...