【问题标题】:Checking if hash value has a text检查哈希值是否有文本
【发布时间】:2016-10-29 22:26:36
【问题描述】:

我有一个哈希:

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

基本上,这是在查看哈希值并检查哈希值是否包含大学名称作为输入。

例如,用户输入可以是“Oxford University”,并且在哈希中存储为“Oxford”。用户需要输入,因为它存储在哈希中才能被分配一个分数,但我希望如果用户输入“牛津大学”,那么应该选择哈希值“牛津”然后通过。

这一切都很好,但.include? 不能正常工作,我仍然需要输入确切的单词。

【问题讨论】:

  • Enumerable#any? 返回一个布尔值。 hashed_topuniversities.any? { ... }.each 不行。
  • 同意。你会想要做正则表达式来匹配链接的一部分。可选地,您可以使用模糊匹配来找到最匹配的键,但这似乎有点矫枉过正:P
  • 考虑用case 声明dotnetperls.com/case-ruby 替换您的if。这将有助于清理您的代码。此外,您在 each 方法之后缺少关闭 end 以匹配 do

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


【解决方案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 调用了大学名称和用户输入。现在比较它们不区分大小写。

【讨论】:

    【解决方案2】:

    我认为您的方法行不通(无论如何,在现实生活中)。 “牛津大学”很简单——只要寻找“牛津”这个词的存在。 “堪萨斯大学”呢?你会尝试匹配“堪萨斯”吗? “堪萨斯州立大学”呢?

    此外,某些大学通常使用众所周知的首字母缩略词或缩写名称,例如“LSE”、“UCLA”、“USC”、“SUNY”、“LSU”、“RPI”、“Penn State” ”、“乔治亚理工学院”、“伯克利”和“加州理工学院”。您还需要考虑大学名称(例如,“University of加利福尼亚、洛杉矶”)。

    对于任何严肃的申请,我认为您需要为每所大学构建所有常用名称的列表,然后要求这些名称与给定的大学名称完全匹配(在删除标点符号和小词之后)。您可以通过修改哈希 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),将大学名称映射到排名。这些名称由hashed_top_universities 的内部散列中的键:names 的值的元素组成,以及包含该散列中的键的完整大学名称,在它们被小写和标点符号和“小词”之后已被删除。

    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 
    

    【讨论】:

      猜你喜欢
      • 2013-07-06
      • 1970-01-01
      • 1970-01-01
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 2011-05-19
      • 1970-01-01
      • 2014-04-06
      相关资源
      最近更新 更多