Ruby匹配来自第一个和第二个数组的元素

时间:2016-07-19 20:53:12

标签: arrays ruby comparison

我有两个数组。第一个是带有名称和数量的字符串数组。第二个是一系列字母。

li.menu-item {
    position: relative;
    top: 50px;
    left: 300px;
}

我想创建第三个数组,根据a2对来自a1的内容进行排序,并根据第一个数组中的信息返回数字。因为a2有" B"和" Z",我需要扫描第一个数组,查找以字母B和Z开头的所有条目,并加上数字。

我的最终目标是在第三个数组上返回总和,如下所示:

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

因为" A"不是在a2上,它不计算在内。

我能够从a1中提取信息:

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

我在比较a1和a2时遇到了麻烦。我尝试过不同的方法,例如:

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

可选地,

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

我认为要么解决它,但我不能把它想到工作代码。我该如何实现这两种方法?有没有更有效的方法呢?

4 个答案:

答案 0 :(得分:2)

我将如何做到这一点:

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中,方法是将值与第二个数组中包含的每个第一个字母相加。

第二步提供所需的输出

如果您想要哈希,只需取消最后一次调用地图,您就可以了。

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

答案 1 :(得分:2)

根据您的要求运行,您想要将其转为:

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

答案 2 :(得分:1)

不是定义像Array这样的["B = 200", "Z = 100"],而是将其定义为映射 - 即以下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中第一个字母为哈希键字符的元素。
  • inject(0) {|sum, str| sum += str[/\d+/].to_i}将所有数字相加,保护措施默认为零(而不是意外地将nil抛出)。

答案 3 :(得分:1)

这与@ engineermnky的答案非常相似。

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"]