0

In Ruby I'm selecting some hash values by key names this way

new_values = my_hash.values_at(:value2, :value3, :value6, :value8).select {|a| !a.empty?}

and what about this? It's not working.

new_values = my_hash.values_at(:value2, :value3, :value6, :value8).select(&:!empty?)

5 Answers5

4

As Sergio explained there is no way to do this with standard Ruby since the expression you are using won't parse. One can hack something together so it works though (of course reject would be the way to go here):

['1', '', '11', ''].select(&fn(:empty?, :!))
#=> ["1", "11"]

Here's the implementation of fn as used in my extension library:

def fn(*funs)
  -> x do
    funs.inject(x) do |v,f|
      Proc === f ? f.call(v) : v.send(f)
    end
  end
end
Michael Kohl
  • 66,324
  • 14
  • 138
  • 158
  • I think, he wanted to do that to save a couple of characters. This approach does neither save space, nor is cleaner. But it's nice to have options :) – Sergio Tulentsev Sep 04 '12 at 10:41
  • Sure, but he said he wanted alternatives. :-) I upvoted your answer cause it makes the most sense to me. – Michael Kohl Sep 04 '12 at 12:05
3

It doesn't work, because there's no method with name !empty?. And this name is illegal in ruby, AFAIK. You either have to use full lambda form (as in your first snippet) or use reject

['1', '', '11', ''].select(&:empty?) # => ["", ""]
['1', '', '11', ''].reject(&:empty?) # => ["1", "11"]
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
1

Talking about alternatives:

Not = 
  lambda do |x|
    p = x.to_proc 
    lambda do |*ys|
      !p[*ys]
    end
  end

['1', '', '11', ''].select(&Not[:empty?])

Can be easily extended to more interesting cases like compositions, fanouts.

Victor Moroz
  • 9,167
  • 1
  • 19
  • 23
0

The inverse method for empty? is any?. With that you can achieve your goal by using

new_values = my_hash.values_at(:value2, :value3, :value6, :value8).select(&:any?)
Holger Just
  • 52,918
  • 14
  • 115
  • 123
0

In the spirit of my answer here:

class Symbol
  def on
    ->(*args) { yield(*args).send(self) }
  end
end

['1', '', '11', ''].select(&:!.on(&:empty?))
# => ["1", "11"] 
Community
  • 1
  • 1
Uri Agassi
  • 36,848
  • 14
  • 76
  • 93