如果

时间:2017-09-28 21:57:31

标签: ruby

我有一个查看5个变量的if,其中一些可能是nil。我有以下代码工作,但它感觉非常混乱。它使用的假设是被测试的字符串不是100 *,但它不能,但不管这是否有更好的方法。

m['search2']  = '*' * 100 if m['search2'].nil?
m['search3']  = '*' * 100 if m['search3'].nil?
m['exclude1'] = '*' * 100 if m['exclude1'].nil?
m['exclude2'] = '*' * 100 if m['exclude2'].nil?

if ( @title.upcase.index( m['search1'] ) || @title.upcase.index( m['search2']) || @title.upcase.index( m['search3']) ) &&
   !(@title.upcase.index( m['exclude1']) || @title.upcase.index( m['exclude1']) ) then
  exclude = true
end 

只是为了澄清,鉴于答案涉及设置默认值的更好方法,虽然这很好,但我希望我能在if中做一些聪明的事情,因为它实际上必须设置默认值,感觉很乱。 / p>

4 个答案:

答案 0 :(得分:1)

除非您处理的情况是,无论出于何种原因,其中一个值可能是文字false,那么您的生活将非常方便。只需定义一些默认值:

DEFAULT_TERM = '*' * 100
DEFAULTS = {
  'search2' => DEFAULT_TERM,
  'search3' => DEFAULT_TERM,
  'exclude1' => DEFAULT_TERM,
  'exclude2' => DEFAULT_TERM
}

然后您可以将其合并到:

m = DEFAULTS.merge(m)

m中未定义的任何内容将自动保留为默认值。您可能需要先清理m

m = DEFAULTS.merge(m.compact)

删除任何nil值。

需要注意的另一件事是省略像then这样的虚假语法。这没有必要,而且基本上没用。

如果您将结构重新组织成这样的结构,那么您可以更轻松地实施更灵活的搜索:

{
  'search' => [ 'term1', 'term2', 'term3' ],
  'exclude' => [ 'exclude1', 'exclude2', 'exclude3' ]
}

从那时起,您可以使用简单的迭代。

答案 1 :(得分:1)

从简化开始:

m['search2']  = '*' * 100 if m['search2'].nil?

更好地表达为:

m['search2'] ||= '*' * 100

然后使整个事物成为一个循环(为了清晰起见,也使字符串变为常量):

STARS = '*' * 100

%w(search2 search3 exclude3 exclude2).each { |key|
  m[key] ||= STARS
}

虽然如果你只是默认这样做,那么有一个更好的方式,如tadman所说。

答案 2 :(得分:1)

无论何时重复代码,都应该考虑使用循环或方法。这是一个使用循环的示例,以便您可以避免重写

search_keys = ['search2', 'search3']
exclude_keys = ['exclude1', 'exclude2']

search_keys.each do |key|
  m[key] = '*' * 100 if m[key].nil?
end

exclude_keys.each do |key|
  m[key] = '*' * 100 if m[key].nil?
end

答案 3 :(得分:1)

似乎你正在尝试解决你在String#index上传递的错误,当它作为参数传递时,而不是它预期的字符串。

在这种情况下,如果你考虑一下你真正想要达到的目标,那就有一个更简单(更惯用的解决方案)。在您的情况下,如果exclude包含任意可选的搜索字词,则您希望将true设置为@title,并排除任何可选的排除字词。

这可以通过以下方法实现。请注意,如果不是带有“魔术”键名称的Hash,您可以将术语设为两个数组,一个用于搜索术语,一个用于排除术语。然后,您的方法也可以扩展为更多术语,而无需进行调整。

def exclude?(m)
  # upcase the @title only once for performance
  upcased_title = @title.upcase

  # Depending on the m argument, you might be able to further
  # improve this to get rid of the repetition 
  exclude_terms = [
    m['exclude1'],
    m['exclude2']
  ].compact
  # ^^^^^^^ Compacting on an array gets rid on any nil values

  # Same here.
  search_terms = [
    m['search1'],
    m['search2'],
    m['search3']
  ].compact
  # ^^^^^^^ Same for the search terms

  # We use include? instead of index to better convey our meaning
  return false if exclude_terms.any? { |term| upcased_title.include?(term) }
  return true if search_terms.any? { |term| upcased_title.include?(term) }

  # TODO: what should happen in neither an exclude term nor
  # a search term was found?
end

请注意,您的问题中的条件似乎是倒退的。如果搜索字词匹配但没有排除字词,则将exclude设置为false。你可能的意思恰恰相反。