检查哈希值是否有文本

时间:2016-06-27 19:35:12

标签: ruby-on-rails ruby ruby-on-rails-4 hash

我有一个哈希:

universityname = e.university
topuniversities = CSV.read('lib/assets/topuniversities.csv',{encoding: "UTF-8", headers:true, header_converters: :symbol, converters: :all})
hashed_topuniversities = topuniversities.map {|d| d.to_hash}

hashed_topuniversities.any? {|rank, name| name.split(' ').include?(universityname) }.each do |s|
  if s[:universityrank] <= 10
    new_score += 10
  elsif s[:universityrank] >= 11 && s[:universityrank] <= 25
    new_score += 5
  elsif s[:universityrank] >= 26 && s[:universityrank] <= 50
    new_score += 3
  elsif s[:universityrank] >= 51 && s[:universityrank] <= 100
    new_score += 2
  end

基本上这样做是查看哈希并检查哈希值是否包含大学名称是输入。

例如,用户输入可以是“牛津大学”,并且在哈希中它存储为“牛津大学”。用户需要键入存储在哈希中的内容才能分配分数,但我希望如果用户输入“牛津大学”,则应选择哈希值“牛津”然后通过。

此处的其他所有工作正常,但.include?无法正常工作,我仍需要输入确切的字词。

2 个答案:

答案 0 :(得分:1)

hashed_topuniversities = topuniversities.map &:to_hash

univ = hashed_topuniversities.detect do |rank, name|
  name.downcase.split(' ').include?(universityname.downcase)
end

new_score += case univ[:universityrank]
             when -Float::INFINITY..10 then 10
             when 11..25 then 5
             when 26..50 then 3
             when 50..100 then 2
             else 0
             end

除了在更惯用的ruby方面的一些代码改进之外,主要的变化是downcase在大学名称和用户输入上调用。现在他们被比较不区分大小写。

答案 1 :(得分:0)

我认为你的方法无论如何都会有效(无论如何)。 &#34;牛津大学&#34;是一个简单的 - 只是寻找这个词的存在,&#34;牛津&#34;。那么&#34;堪萨斯大学&#34;?你会不会尝试匹配&#34;堪萨斯&#34;?那么&#34;堪萨斯州立大学&#34;?

此外,一些大学通常被称为缩写词或缩写名称,例如&#34; LSE&#34;,&#34; UCLA&#34;,&#34; USC&#34;, &#34; SUNY&#34;,&#34; LSU&#34;,&#34; RPI&#34;,&#34; Penn State&#34;,&#34; Georgia Tech&#34;,&#34 ;伯克利&#34;和&#34; Cal Tech&#34;。你还需要考虑标点符号和&#34;小词&#34; (例如, &#34; at&#34;,&#34;&#34;,&#34;&#34; )在大学名称中(例如, &#34;加州大学洛杉矶分校&#34;)。

对于任何严肃的申请,我认为您需要为每所大学构建一个所有常用名称的列表,然后要求这些名称与给定的大学名称之间完全匹配(在标点符号和删除的小词之后)。你可以通过修改哈希hashed_top_universities来做到这一点,也许是这样的:

hashed_top_universities
  #=> { "University of California at Berkeley" => 
  #       { rank: 1, names: ["university california", "berkeley", "cal"] },
  #     "University of California at Los Angeles" =>
  #       { rank: 2, names: ["ucla"] },
  #     "University of Oxford" =>
  #       { rank: 3, names: ["oxford", "oxford university"] }
  #   }

某些大学的名称包含非ASCII字符,这是一个更复杂的问题(我不会解决)。

以下是您可以编码的方式。

鉴于大学名称,第一步是构建一个将大学名称映射到排名的哈希(reverse_hash)。名称由:names内部哈希值中的键hashed_top_universities的值的元素组成,以及包含该哈希中的键的完整大学名称,在它们已经下降和标点符号之后&#34;小词&#34;已被删除。

PUNCTUATION = ",."
EXCLUSIONS  = %w| of for the at u |
SCORE = { 1=>10, 3=>7, 25=>5, 50=>3, 100=>2, Float::INFINITY=>0 }

reverse_hash = hashed_top_universities.each_with_object({}) { |(k,v),h|
  (v[:names] + [simplify(k)]).each { |name| h[name] = v[:rank] } }
  #=> {"university california"=>1, "berkeley"=>1, "cal"=>1,
  #      "university california berkeley"=>1,
  #    "ucla"=>2, "university california los angeles"=>2,
  #    "oxford"=>3, "oxford university"=>3, "university oxford"=>3}

def simplify(str)
  str.downcase.delete(PUNCTUATION).
      gsub(/\b#{Regexp.union(EXCLUSIONS)}\b/,'').
      squeeze(' ')
end

def score(name, reverse_hash)
  rank = reverse_hash[simplify(name)]
  SCORE.find { |k,_| rank <= k }.last
end

试试吧。

score("University of California at Berkeley", reverse_hash)
  #=> 10 
score("Cal", reverse_hash)
  #=> 10 
score("UCLA", reverse_hash)
  #=> 7 
score("Oxford", reverse_hash)
  #=> 7