簡體   English   中英

Ruby將第一個數組中的元素與第二個數組進行匹配

[英]Ruby match elements from the first with second array

我有兩個數組。 第一個將是一個包含名稱和數量的字符串數組。 第二個是字母數組。

a1 = ["ASLK 50", "BSKD 150", "ZZZZ 100", "BSDF 50"]
a2 = ["B", "Z"]

我想創建第三個數組,以基於a2對a1中的內容進行排序,並根據第一個數組中的信息返回數字。 由於a2具有“ B”和“ Z”,因此我需要掃描第一個數組以查找所有以字母B和Z開頭的條目,並將它們相加。

我的最終目標是在第三個數組上返回總和,如下所示:

a3 = ["B = 200", "Z = 100"]

由於“ A”不在a2上,因此不計算在內。

我能夠從a1中提取信息:

arr = a1.map{|el| el[0] + " : " + el.gsub(/\D/, '\1')}
#=> ["A : 50", "B : 150", "Z : 100", "B : 50"]

我在比較a1和a2時遇到問題。 我嘗試了不同的方法,例如:

a1.find_all{|i| i[0] == a2[0]} #=> only returns the first element of a2. How can I iterate through a2?

或者,

i = 0
arr_result = []
while i < (arr.length + 1)
    #(append to arr_result the number from  a1 if a1[i][0] matches a2[i])

我認為任何一個都可以解決它,但是我不能將兩個想法都歸結為工作代碼。 如何實現這兩種方法? 有更有效的方法嗎?

這是我的處理方式:

a1 = ["ASLK 50", "BSKD 150", "ZZZZ 100", "BSDF 50"]
a2 = ["B", "Z"]
a3 = a1.each_with_object(Hash.new(0)) do |a,obj|
  obj[a[0]] += a.split.last.to_i if a2.include?(a[0]) 
end.map {|a| a.join(" = ")}
#=>["B = 200", "Z = 100"]

第一步,通過將第二個數組中包含的每個第一個字母的值相加,將它們全部添加到Hash

第二步提供所需的輸出

如果您想要哈希,只需取消最后一次調用map即可。

{"B" => 200, "Z" => 100}

在滿足您的要求的情況下,您要更改以下內容:

a1 = ["ASLK 50", "BSKD 150", "ZZZZ 100", "BSDF 50"]
a2 = ["B", "Z"]

變成: a3 = ["B = 200", "Z = 100"]

a3 = a2.map do |char|
  sum = a1.reduce(0) do |sum, item|
    name, price = item.split(" ")
    sum += price.to_i if name[0].eql?(char)
    sum
  end
  "#{char} = #{sum}"
end

與其定義像["B = 200", "Z = 100"]這樣的Array不如將其定義為映射 -即以下Hash對象,將更為明智:

{"B" => 200, "Z" => 100}

至於實現,有很多方法可以做到。 這只是一種方法:

a1 = ["ASLK 50", "BSKD 150", "ZZZZ 100", "BSDF 50"]
a2 = ["B", "Z"]
result = a2.map do |letter|
  [
    letter,
    a1.select {|str| str[0] == letter}
      .inject(0) {|sum, str| sum += str[/\d+/].to_i}
  ]
end.to_h

puts result # => {"B"=>200, "Z"=>100}

說明:

  • 在頂層,我使用Array#to_h對的數組: [["B", 200], ["Z", 100]]轉換為Hash{"B" => 200, "Z" => 100}
  • a1.select {|str| str[0] == letter} a1.select {|str| str[0] == letter}僅從a1選擇其第一個字母為哈希鍵的元素。
  • inject(0) {|sum, str| sum += str[/\\d+/].to_i} inject(0) {|sum, str| sum += str[/\\d+/].to_i}將所有數字加起來,並且安全防護默認為零(而不是意外地拋出nil )。

這與@engineersmnky的答案非常相似。

r = /
    \A[A-Z] # match an upper case letter at the beginning of the string
    |       # or
    \d+     # match one or more digits
    /x      # free-spacing regex definition mode

a1.each_with_object(Hash.new(0)) do |s,h|
  start_letter, value = s.scan(r)
  h[start_letter] += value.to_i if a2.include?(start_letter)
end.map { |k,v| "#{k} = #{v}" }
  #=> ["B = 200", "Z = 100"] 

Hash.new(0)通常被稱為“計數哈希”。 有關說明,請參見文檔中有關類方法Hash :: new的內容。

正則表達式匹配字符串的首字母或一個或多個數字。 例如,

"ASLK 50".scan(r)
  #=> ["A", "50"]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM