我有一個任務是輸出所有命令列引數的總和,在出現一堆錯誤并意識到 ARGV.to_i 不會將所有元素轉換為整數之后,我想出了以下解決方案。
def argv_sum()
index = 0
sum = 0
ARGV.each do |a|
ARGV[index] = ARGV[index].to_i
index = 1
end
puts ARGV.sum
end
argv_sum()
或者
def argv_sum()
index = 0
sum = 0
ARGV.each do |a|
sum = ARGV[index].to_i
index = 1
end
puts sum
end
argv_sum()
然后我在網上查看并意識到我可以將陣列中的所有元素轉換為整數,并且我假設(如果我錯了,請糾正我),下面是程式最好/最有效的代碼,也是唯一的方法將陣列的所有元素在一行上轉換為整數,而不依賴于回圈。我也假設sum = ARGV[index].to_i比ARGV[index] = ARGV[index].to_i
def argv_sum()
ARGV.map!(&:to_i)
puts ARGV.sum()
end
argv_sum
但我感到困惑的是mapvs map!。我知道前者用一個新陣列替換了陣列,后者更改了原始陣列。但如果我map出于任何原因使用,我將如何區分它和原始。例如,以下(與上述幾乎相同)不起作用。
def argv_sum()
ARGV.map(&:to_i) #map is used here instead of map!
puts ARGV.sum
end
argv_sum
.map創建一個新陣列,但是我如何在需要時專門使用這個新陣列或使用舊陣列?因為程式只是假設我使用的是舊陣列,所以我會得到一個“字串不能被強制轉換為整數”的錯誤。它與舊陣列具有相同的名稱,無論我是否使用ARGV或類似array_test = []
用我解決原始求和問題的所有方法,有沒有一種方法可以檢查哪個最有效。(最適合程式,讓程式運行得更高效、更快/節省空間/等等?)對于這些程式以及我將來可能想撰寫的任何其他程式。
uj5u.com熱心網友回復:
.map創建一個新陣列,但是我如何在需要時專門使用這個新陣列或使用舊陣列?
Ruby 和大多數編程語言(但不是全部)一樣,有一種叫做variables 的東西。變數提供了兩件事情:它可以讓你到指定標簽的東西,它可以讓你重新參考的東西使用的標簽。
分配變數的語法是
variable = expression
從那一刻起,變數variable參考了通過評估回傳的物件expression。所以,你可以做這樣的事情:
def argv_sum
integers = ARGV.map(&:to_i)
puts integers.sum
end
argv_sum
但是,我認為該變數不會向代碼添加任何內容,它并沒有真正使代碼更易于閱讀和/或維護,因此我將擺脫它:
def argv_sum = puts(ARGV.map(&:to_i).sum)
argv_sum
請記住,變數的兩個目的是稍后參考一個物件,并給它一個標簽。在這種情況下,我們并沒有真正在稍后參考物件,而是立即參考它,并且標簽并沒有真正增加代碼的清晰度。因此,變數只是多余的絨毛,可以消失。
請注意,正如您在檔案中看到的那樣,Enumerable#sum在計算總和之前采用一個塊來轉換每個元素……換句話說,Enumerable#sum使用塊引數將映射和總和融合為一個操作,因此我們實際上可以這樣做
def argv_sum = puts(ARGV.sum(&:to_i))
argv_sum
就我個人而言,我不喜歡混合計算和輸入/輸出,因為這會使代碼更難測驗。例如,此代碼只能通過將其放入腳本中進行測驗,然后撰寫第二個腳本,該腳本使用不同的命令列引數呼叫第一個腳本并決議命令列輸出。這是復雜、脆弱且容易出錯的。如果我們可以通過簡單地呼叫一個方法來測驗它會更好。
所以,我會把列印和求和部分分開。請注意,該方法的名稱已經表明無論如何:argv_sum聽起來該方法回傳 的總和ARGV,但實際上并非如此:它回傳nil并僅列印的總和ARGV。所以,讓我們解決這個問題:
def argv_sum = ARGV.sum(&:to_i)
def print_argv_sum = puts(argv_sum)
print_argv_sum
Now, we have separated the input / output part from the computation part … or, have we? No, actually we have not: we have separated the printing part from the computation part, but there is still a somewhat "hidden" input part: ARGV itself is kind-of a "magic" input from the outside world, so we should separate that out, too:
def sum_array_of_strings(ary) = ary.sum(&:to_i)
def print_array_sum(ary, output_stream = default_output) =
output_stream.puts(sum_array_of_strings(ary))
def print_argv_sum(output_stream = default_output) =
print_array_sum(argv, output_stream)
def argv = ARGV
def default_output = $>
print_argv_sum
雖然這對于一個簡單的例子來說可能有點矯枉過正,但這段代碼現在允許我們輕松測驗代碼的幾乎所有方面,而無需任何輸入/輸出。我們可以通過呼叫sum_array_of_strings并向其傳遞我們選擇的陣列來測驗求和是否有效。我們可以通過呼叫print_array_sum并向它傳遞我們選擇的陣列和一個我們可以稍后檢查的假輸出流(例如StringIO來自stringio標準庫的實體)來測驗列印是否有效。我們可以通過覆寫default_output_stream和argv方法來測驗整個邏輯是否正確掛在一起,以回傳我們選擇的物件。
這些都不需要實際傳遞任何命令列引數或決議列印輸出:
#!/usr/bin/env ruby
# frozen_string_literal: true
require 'minitest/autorun'
require 'stringio'
class TestArgvSummer < Minitest::Test
def setup
@fake_output = StringIO.new
@fake_argv = %w[1 2 3 4 5]
end
def test_that_sum_array_of_strings_sums_correctly
assert_equal 0, sum_array_of_strings([])
assert_equal 42, sum_array_of_strings(%w[42])
assert_equal 65, sum_array_of_strings(%w[23 42])
assert_equal 15, sum_array_of_strings(@fake_argv)
end
def test_that_print_array_sum_works_correctly
@fake_output.rewind
print_array_sum(@fake_argv, @fake_output)
assert_equal "15\n", @fake_output.string
end
end
uj5u.com熱心網友回復:
在 ARGV 上使用 Array#sum
您不會顯示您的輸入或您如何呼叫您的代碼,因此很難提供適合您特定用例的建議。然而,從更一般的意義上講,Ruby 有很多內置方法,可以使求和 Integer 值變得非常簡單。
ARGV是一個特殊的陣列是將引數傳遞到你的程式的字串,你可以使用陣列#總和將它們全部加起來,一旦你將它們轉換為整數,浮點數,還是真的什么,#responds_to? : 。例如,考慮以下 Ruby 腳本:
#!/usr/bin/env ruby
# call #to_i on each each element of ARGV,
# sum all the elements, and output the
# result
puts ARGV.map(&:to_i).sum
從您的 shell 中,您可以像這樣呼叫程式:
$ ruby sum.rb 5 10 15
30
也沒有什么可以阻止您在 irb 或 pry 中直接分配給 ARGV。請記住,當來自命令列的ARGV始終包含字串值,因此當您沒有將它直接分配為 REPL 中的非字串時,您必須執行從字串到數字的轉換。
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/351142.html
