I have an inject call
[2,4,6].inject(true) { |res, val| res && val % 2 == 0 }
and want to send the && operator to inject as in inject(0, :+). How can I do that?
You can't because && and ||, unlike other operators, are not syntacic sugar for methods (i.e. there is no method called && or ||), so you can't reference them using a symbol.
However you can avoid using inject to compute the logical conjunction or disjunction of an array of boolean values, replacing it with all? or any? respectively, because for any array the following conditions hold:
ary.inject(true) { |res, b| res && b } == ary.all?
ary.inject(false) { |res, b| res || b } == ary.any?
So, for example, the code you posted could be rewritten as:
[2,4,6].map(&:even?).all?
# => true
Update: obviously my latter example is not the right way to express this computation, falsetru's answer is much faster:
require 'fruity'
compare(
-> { (0..1000).map(&:even?).all? },
-> { (0..1000).all?(&:even?) }
)
Running each test 1024 times. Test will take about 2 seconds.
Code 2 is faster than Code 1 by 111x ± 10.0
How about using Enumerable#all?
[2,4,6].all? &:even?
# => true
[2,4,6,5].all? &:even?
# => false
If you want to use inject, you need to define an instance method.
class Object
def is_even(val)
self && val % 2 == 0
end
end
[2,4,6].inject(true, :is_even) # => true
[1,2,4,6,5].inject(true, :is_even) # => false
'&&' is not a method, hence you can't inject it. However you can inject & method.
[2,4,6,5].map(&:even?).inject(true, :&)
Which will do the same
NOTE: This however should not be done, as it is extremely risky and might cause unexpected consequences (if run on collection containing at least one non-boolean (true, false, nil) value). You should always use any? or all? methods instead.
inject(0, :+) would add all the elements of the array, regardless of what the content of the elements are (odd, even, etc).
If you want to inject(true, &:&&) (I know this doesn't work), your array should be an array of boolean values for your question to make sense, which would be the same as: [true, false].all?
important:
you can't pass both block arg and actual block which means you can't check if it's even inject an && at the same time.
If you insist, try this out:
[2,4,6].inject(true, & lambda { |x,y| x && y })
=> 6
This is the equivalent of what you're asking for (which I still don't totally understand)
Related
I want to be able to find a custom class in my set given just a string. Like so:
require 'set'
Rank = Struct.new(:name, keyword_init: true) {
def hash
name.hash
end
def eql?(other)
hash == other.hash
end
def ==(other)
hash == other.hash
end
}
one = Rank.new(name: "one")
two = Rank.new(name: "two")
set = Set[one, two]
but while one == "one" and one.eql?("one") are both true, set.include?("one") is still false. what am i missing?
thanks!
Set is built upon Hash, and Hash considers two objects the same if:
[...] their hash value is identical and the two objects are eql? to each other.
What you are missing is that eql? isn't necessarily commutative. Making Rank#eql? recognize strings doesn't change the way String#eql? works:
one.eql?('one') #=> true
'one'.eql?(one) #=> false
Therefore it depends on which object is the hash key and which is the argument to include?:
Set['one'].include?(one) #=> true
Set[one].include?('one') #=> false
In order to make two objects a and b interchangeable hash keys, 3 conditions have to be met:
a.hash == b.hash
a.eql?(b) == true
b.eql?(a) == true
But don't try to modify String#eql? – fiddling with Ruby's core classes isn't recommended and monkey-patching probably won't work anyway because Ruby usually calls the C methods directly for performance reasons.
In fact, making both hash and eql? mimic name doesn't seem like a good idea in the first place. It makes the object's identity ambiguous which can lead to very strange behavior and hard to find bugs:
h = { one => 1, 'one' => 1 }
#=> {#<struct Rank name="one">=>1, "one"=>1}
# vs
h = { 'one' => 1, one => 1 }
#=> {"one"=>1}
what am i missing?
What you are missing is that "one" isn't in your set. one is in your set, but "one" isn't.
Therefore, the answer Ruby is giving you is perfectly correct.
All that you have done with your implementation of Rank is that any two ranks with the same name are considered to be the same by a Hash, Set, or Array#uniq. But, a Rank is not the same as a String.
If you want to be able to have a set-like data structure where you can look up things by one of their attributes, you will have to write it yourself.
Something like (untested):
class RankSet < Set
def [](*args)
super(*args.map(&:name))
end
def each
return enum_for(__callee__) unless block_given?
super {|e| yield e.name }
end
end
might get you started.
Or, instead of writing your own set, you can just use the fact that any arbitrary rank with the right name can be used for lookup:
set.include?(Rank.new(name: "one"))
#=> true
# even though it is a *different* `Rank` object
Using Ruby I want to evaluate all items in an array, and return true if they all pass a conditional test.
I can do this using e.g. array.all? { |value| value == 2 }
So:
> array=[2,2]
> array.all? { |value| value == 2 }
=> true
> array=[2,3]
> array.all? { |value| value == 2 }
=> false
Great!
But, why does an empty array pass this test?
> array=[]
> array.all? { |value| value == 2 }
=> true
Shouldn't this return false?
And if I need it to return false, how should I modify the method?
This is a vacuous truth. It's the standard interpretation of a universal quantification, i.e. a
collection.all? { |x| some_predicate(x) }
over an empty collection, but it's known to strike people as counter-intuitive when they first see it in a formal setting. One nice way to think about why this is the preferred semantics is to think about how you would implement all?.
To make your test require that the array is non-empty, just do
array.any? && array.all? { |x| x == 2 }
Note that array.any? is fast no matter how large the array, whereas array.all? { |x| x == 2 } can be slow, depending on how big array is and how rare 2 is in it. So put the array.any? first.
Also note, there are degenerate cases where this won't work, for instance if array is [nil] or [false]. If cases like this might come up, replace array.any? with array.any? { true }.
In Ruby you can never loop over an empty collection (array, hashes, etc.), so in your case your block never gets executed. And if the block never gets executed, all? returns true (there is no condition to make the result false).
Read about all? in the Ruby documentation.
You can simply achieve your goal by
!array.empty? && array.all? { |value| value == 2 }
The documentation says : "The method returns true if the block never returns false or nil.."
In the case of an empty array the block never executes and hence the method will always return true. As far as returning false is concerned you'll have to arr.empty?
There is no item in that array that doesn't pass the test. I think you may need to throw in a test for array length.
Just go
!(array.empty? || array.any? {|x| x != 2})
(Which has the added advantage of failing fast—that is, it can be evaluated properly without having to scan the whole array.)
Since there is no item in the array that FAILS that test, it returns true. So just use somehting like:
array.size > 0 and array.all? { |value| value == 2}
Or something like that.
Zeroes, empty collections, empty matrices and such have always been a bit special, if not outright problematic. Greeks knew well why they didn't count 0 among natural integers.
Method all? would be the first to ask you "why are you calling me on an empty array?" What do you mean by "all?", when there is nothing in there? That's a contradiction. And the method does short thinking, and answers true for the reasons outlined in the other three answers. Remember, you are at fault for talking about "all elements" of an empty array to begin with.
As Amit Kumar Gupta writes, it is the standard interpretation of universal quantification. I have no idea why you expect it to be false. Here, you can see it should be true by inference.
Universal quantification is equivalent to conjunction, thus ("<=>" means equivalent):
"for all x in [a, b, c], P(x)" <=> "P(a) and P(b) and P(c)"
Notice that any proposition is equivalent to the conjunction of true and itself, so:
"for all x in [a, b, c], P(x)" <=> "true and P(a) and P(b) and P(c)"
If you lessen the elements in the set to two, you get:
"for all x in [a, b], P(x)" <=> "true and P(a) and P(b)"
and further to one element:
"for all x in [a], P(x)" <=> "true and P(a)"
Now, what happens with the empty set? Naturally,
"for all x in [], P(x)" <=> "true"
By noticing that existential quantification is equivalent to disjunction, you can also see that you should expect false with existential quantification over an empty set.
The source of all? method says that it uses static variable(which is initially set to true) and then performs the AND operation between the static variable value and the result of the iteration finally returns this static variable as a result.
as the array is Empty ruby will never iterate on this empty array and as a result of this all? method will return the static variable which was set to true.
Make sure the array is not empty first.
Then:
array.compact.present? && array.all? {|x| x != 2}
How is Proc#== evaluated? RDoc says:
prc == other_proc → true or false
Returns true if prc is the same object as other_proc, or if they are both procs with the same body.
But it is not clear what counts as having "the same body". One condition seems to be that the arity must be the same:
->{} == ->{} # => true
->{} == ->x{} # => false
->x{} == ->x{} # => true
->x{} == ->y{} # => true
->x{} == ->y,z{} # => false
But there is more than that. As RDoc says, the body matters:
->{nil} == ->{nil} # => true
->{nil} == ->{false} # => false
->{false} == ->{false} # => true
But at the same time, it looks like the proc is not fully evaluated:
->{} == ->{nil} # => false
->{false} == ->{1 == 2} # => false
To what extent is the body evaluated?
This has changed in Ruby 2.0, so you should not try to compare Procs. They won't be == unless they are exactly the same object.
The discussion can be found here.
If you really need to compare the code of two blocks and are using MRI, you can play around with RubyVM::InstructionSequence.disassemble(block), or even better in Ruby 2.0 RubyVM::InstructionSequence.of(block).
To answer that question lets look at the proc comparison code
static VALUE
proc_eq(VALUE self, VALUE other)
{
if (self == other) {
return Qtrue;
}
else {
if (rb_obj_is_proc(other)) {
rb_proc_t *p1, *p2;
GetProcPtr(self, p1);
GetProcPtr(other, p2);
if (p1->envval == p2->envval &&
p1->block.iseq->iseq_size == p2->block.iseq->iseq_size &&
p1->block.iseq->local_size == p2->block.iseq->local_size &&
MEMCMP(p1->block.iseq->iseq, p2->block.iseq->iseq, VALUE,
p1->block.iseq->iseq_size) == 0) {
return Qtrue;
}
}
}
return Qfalse;
}
The first if branch is quite simple - compare it two procs are the same object.
The second is little bit more tricky. It checks that both of the procs have same envval, size of the iseq(proc implementation), local variables size and compares that the both implementations are identical. That means that proc equality is checked on a syntax level, not on proc result.
Lets take https://gist.github.com/4611935
First sample works just fine because number of local variables are the same and the sequence of operations are the same. Assign 123 to local variable. The second sample treated as not same because operation sequence differs - you assign 123 to different variables.
But yes, proc comparison is pretty confusing and has been removed form ruby 2.0 I presume. Now procs are compared as a regular object by its id.
This article mentions 4 ways to invoke procs in ruby 1.9, and === is one of them. I don't understand why this would be done this way at all. Does it have any relationship to the normal meaning of === (asking if the two objects are the same object)?
irb(main):010:0> f =-> n {[:hello, n]}
=> #
irb(main):011:0> f.call(:hello)
=> [:hello, :hello]
irb(main):012:0> f === :hello
=> [:hello, :hello]
irb(main):013:0> Object.new === Object.new
=> false
irb(main):014:0> f === f
=> [:hello, #]
Note that === in Ruby is NOT about equality, unlike JavaScript. It is specifically used for case expressions:
case cats.length
when 42 # Uses 42 === cats.length
puts :uh
when /cool/i # Uses /cool/i === cats.length
puts :oh
when ->(n){ n.odd? || n/3==6 } # Passes cats.length to the proc
puts :my
end
This is what the docs have to say:
It is to allow a proc object to be a target of when clause in the
case statement.
This is a, perhaps contrived, example:
even = proc { |x| x % 2 == 0 }
n = 3
case n
when even
puts "even!"
else
puts "odd!"
end
It works because the case/when is basically executed like this:
if even === n
puts "even!"
else
puts "odd!"
end
The case/when checks which branch to execute by calling === on the arguments to when clauses, picking the first that returns a truthy value.
Despite its similarity to the equality operator (==) it not a stronger or weaker form of it. I try to think of the === operator as the "belongs to" operator. Class defines it so that you can check if an object belongs to the class (i.e. is an instance of the class or a subclass of the class), Range defines it as to check if the argument belongs to the range (i.e. is included in the range), and so on. This doesn't really make the Proc case make more sense, but think of it as a tool for making your own belongs to operators, like my example above; I defined an object that can determine if something belongs to the set of even numbers.
This feature is useful in case construction, when you need to calculate something at the comparing.
is_odd =-> n { n%2 != 0 }
is_even =-> n { n%2 == 0 }
case 5
when is_even
puts "the number is even"
when is_odd
puts "the number is odd"
end
=> the number is odd
Does it have any relationship to the normal meaning of === (asking if the two objects are the same object)?
Actually, that's a common misconception about === in Ruby. It's actually not strictly for Object#object_id comparison (although that is its behavior in many common invocations). In Ruby, === is case subsumption.
Here's the description of === from Object: "Case Equality -- For class Object, effectively the same
as calling #==, but typically overridden by descendants
to provide meaningful semantics in case statements."
Sadly, even though it is comprised of three =, it doesn't have anything even remotely to do with equality :-D
I have an array of arrays, called guid_pairs:
[['a','b','c'],['c','g'],['z','f','b']]
I also have an array, called array_to_check:
['c','a','b']
How can I determine if the array guid_pairs has an element that is equal to array_to_check. Equality should not consider the position of the array elements.
In this example, the check should return true because guid_pairs contains the element ['a','b','c'], which matches ['c','a','b'].
I have tried this, but it seems to always return false even when it should return true:
guid_pairs.any?{|pair| pair.eql?(array_to_check)}
I am using Ruby 1.9.2
There is a set class in the standard library and using sets nicely matches your intent:
require 'set'
a = ['c','a','b']
aa = [['a','b','c'],['c','g'],['z','f','b']]
find_this = Set.new(a)
the_match = aa.find { |x| find_this == Set.new(x) }
That will leave the matching element element of aa in the_match. If you're only interested in existence then you can simply check the truthiness of the_match; or use any? (thanks for the reminder Michael Kohl, I often forget about some of the things in Enumerable):
aa.any? { |x| find_this == Set.new(x) }
No tricks, no magic, and using Set makes it clear that you are, in fact, comparing the arrays as sets.
BTW, your attempted solution:
guid_pairs.any? { |pair| pair.eql?(array_to_check) }
doesn't work because arrays compare element-by-element in order so two arrays are equal if and only if they have equal elements in the same order. The documentation for eql? could be clearer:
Returns true if self and other are the same object, or are both arrays with the same content.
But the == documentation is nice and clear:
Two arrays are equal if they contain the same number of elements and if each element is equal to (according to Object.==) the corresponding element in the other array.
We can look to Object#eql? for some clarification though:
The eql? method returns true if obj and anObject have the same value. Used by Hash to test members for equality. For objects of class Object, eql? is synonymous with ==. Subclasses normally continue this tradition, but there are exceptions.
So == and eql? should behave the same way unless there is a good reason for them to be different.
To see if two arrays contain the same elements, regardless of order, you can use the XOR (exclusive or) operation. It will return an array which contains only elements that are in one array and not the other. If the length of the XOR is zero then the input arrays contain the same elements.
def xor(a, b)
(a | b) - (a & b)
end
guid_pairs.any? { |pair| xor(pair, array_to_check).length != 0 }
A possible solution is to sort the arrays before comparing (or even during comparing):
guid_pairs.any?{|pair| pair.sort.eql?(array_to_check.sort)}
Note that this may not be an optimal solution - it would be more appropriate to have your arrays sorted (nevertheless they are sets in your use case).
for equality of two arrays A and B i normally use:
if(((A-B) + (B-A)).blank?)
puts "equal"
else
"unequal"
end
You can use the following:
sorted_array_to_check = array_to_check.sort
guid_pairs.any?{|pair| pair.sort.eql?(sorted_array_to_check)}
Three solutions:
class Array
def check1 other; other.any?{|e| self - e == e - self} end
def check2 other; other.any?{|e| self | e == self and e | self == e} end
def check3 other; other.any?{|e| self & e == self and e & self == e} end
end
array_to_check.check1(guid_pairs) # => true
array_to_check.check2(guid_pairs) # => true
array_to_check.check3(guid_pairs) # => true
Without defining a method (following Josha's suggestion):
array_to_check.instance_eval{guid_pairs.any?{|e| self - e == e - self}} # => true
array_to_check.instance_eval{guid_pairs.any?{|e| self | e == self and e | self == e}} # => true
array_to_check.instance_eval{guid_pairs.any?{|e| self & e == self and e & self == e}} # => true