根据字母表中字母的位置为单词指定值

时间:2014-03-31 20:55:59

标签: ruby algorithm

我有一系列名字。每个字母的字母表值为1到26。然后将该字母乘以其在列表中的位置。我提出了以下算法:

score = 0
names.each_with_index do |name, index|
    temp = 0
    letters = name.to_s.scan(/(.)/)
    letters.each do |letter|
        temp += 1 if letter.to_s.match(/A/)
        temp += 2 if letter.to_s.match(/B/)
        temp += 3 if letter.to_s.match(/C/)
        temp += 4 if letter.to_s.match(/D/)
        temp += 5 if letter.to_s.match(/E/)
        temp += 6 if letter.to_s.match(/F/)
        temp += 7 if letter.to_s.match(/G/)
        temp += 8 if letter.to_s.match(/H/)
        temp += 9 if letter.to_s.match(/I/)
        temp += 10 if letter.to_s.match(/J/)
        temp += 11 if letter.to_s.match(/K/)
        temp += 12 if letter.to_s.match(/L/)
        temp += 13 if letter.to_s.match(/M/)
        temp += 14 if letter.to_s.match(/N/)
        temp += 15 if letter.to_s.match(/O/)
        temp += 16 if letter.to_s.match(/P/)
        temp += 17 if letter.to_s.match(/Q/)
        temp += 18 if letter.to_s.match(/R/)
        temp += 19 if letter.to_s.match(/S/)
        temp += 20 if letter.to_s.match(/T/)
        temp += 21 if letter.to_s.match(/U/)
        temp += 22 if letter.to_s.match(/V/)
        temp += 23 if letter.to_s.match(/W/)
        temp += 24 if letter.to_s.match(/X/)
        temp += 25 if letter.to_s.match(/Y/)
        temp += 26 if letter.to_s.match(/Z/)
    end
    score += (index+1) * temp
end

puts score

这是非常慢的代码。我希望有人可以向我解释一个更好,更快的方法来完成这项任务。

2 个答案:

答案 0 :(得分:3)

我就是这样做的。

<强>假设

  • 唯一的字符是大写和小写字母和空格。
  • 在将数组的每个元素的所有字符转换为小写字母后,您希望将每个字的a的字母偏移求和,然后乘以数组中字的(基数1)位置

<强>代码

def totals_by_name(names)
  names.each.with_index(1).with_object({}) { |(name,i),tots|
    tots[name] = i*(name.downcase.each_char.reduce(0) { |tot,c|
      tot + c.ord - 'a'.ord + 1 }) }
end

def total(names)
  totals_by_name(names).values.reduce(:+)
end

示例

names = %w{ Joanne Jackie Joe Jethro Jack Jill }
  #=> ["Joanne", "Jackie", "Joe", "Jethro", "Jack", "Jill"] 

total(names)
  #=> 914 

<强>解释

对于方法totals_by_name和上面的数组names

e0 = names.each
  #=> #<Enumerator: ["Joanne", "Jackie", "Joe", "Jethro", "Jack", "Jill"]:each>

我们可以通过将它转换为数组来查看此枚举器将传递的值:

e0.to_a
  #=> ["Joanne", "Jackie", "Joe", "Jethro", "Jack", "Jill"] 

继续,

e1 = e0.with_index(1)
  #=> #<Enumerator: #<Enumerator: ["Joanne", "Jackie", "Joe", "Jethro",
  #     "Jack", "Jill"]:each>:with_index(1)> 
e1.to_a
  #=> [["Joanne", 1], ["Jackie", 2], ["Joe", 3], ["Jethro", 4], ["Jack", 5], ["Jill", 6]]
e2 = e1.with_object({})
  #=> #<Enumerator: #<Enumerator: #<Enumerator: ["Joanne", "Jackie", "Joe",
  #     "Jethro", "Jack", "Jill"]:each>:with_index(1)>:with_object({})> 
e2.to_a
  #=> [[["Joanne", 1], {}], [["Jackie", 2], {}], [["Joe", 3],  {}],
  #    [["Jethro", 4], {}], [["Jack", 5],   {}], [["Jill", 6], {}]] 

我们可以将e2e3视为复合枚举数。

Enumerator#每个都将e2的元素传递给块,并将值赋给块变量。我们可以使用Enumerator#next来查看会发生什么:

(name,i),tots = e2.next
     #=> [["Joanne", 1], {}] 
name #=> "Joanne" 
i    #=> 1 
tots #=> {} 

块计算是:

e3 = name.downcase.each_char
  #=> #<Enumerator: "joanne":each_char> 
e3.to_a # have a look
  #=> ["j", "o", "a", "n", "n", "e"] 

e3.reduce(0) { |tot,c| tot + c.ord - 'a'.ord + 1 }
  #=> 59

有关

c = "j"

这个块计算是:

tot + c.ord - 'a'.ord + 1
  #=> 0 + 106 - 97 + 1
  #=> 10

因此:

tots[name] = i*(name.downcase.each_char.reduce(0) { |tot,c|
  tot + c.ord - 'a'.ord + 1 })    
  #=> tots["Joanna"] = 1*(59)
tots
  #=> {"Joanne"=>59}

其他名称的值类似地计算。方法tots很简单。

答案 1 :(得分:2)

我很可能会选择:

class String
  def points
    each_char.map.with_index do |char, index|
      (char.downcase.ord - 96) * (index + 1)
    end.inject(0, :+)  
  end
end

'Hello'.points  #=> 177