how to find out whether all array elements match some condition? - ruby

I have a big array and I need to know whether all its elements are divisible by 2.
I'm doing it this way, but it's sort of ugly:
_true = true
arr.each { |e| (e % 2).zero? || _true = false }
if _true == true
# ...
end
How to do this without extra loops/assignments?

This will do.
arr.all?(&:even?)

Ruby's got you covered.
if arr.all? {|e| (e % 2).zero?}
There's also any? if you need to check whether at least one element has a given property.

Related

How to remove 3 or more the same character

During my lessons of Ruby I came across of this exercise. I'm trying to remove 3 or more the same charactes in a row. Test Cases Input: abbbaaccada Output: ccada Input: bbccdddcb Output: (Empty string)
So far I have solution which doesn't return expected results:
def playground("abbbaaccada")
count = string.length
string.chars.each_with_index.map { |v, i| (v * (count - i)).capitalize }.join('')
end
output gives me
==> AaaaaaaaaaaBbbbbbbbbbBbbbbbbbbBbbbbbbbAaaaaaaAaaaaaCccccCcccAaaDdA
instead of
==> ccada
Could you please advise?
Edit:
Forgot to add that regexp isn't allowed
There are two challenges here:
Match and remove any run of thee or more characters in a row
Recurse to test again in case the previous step created a new run of three
Here's one way to do it:
THREE_OR_MORE = /(.)\1{2,}/
def three_is_too_many(str)
if str.match? THREE_OR_MORE
str = three_is_too_many(str.gsub(THREE_OR_MORE, ''))
end
str
end
The regexp finds any character ('.'), followed by itself ('\1'), two or more times ('{2,}').
Then the routine either a) removes three or more and tests again or b) returns the string.
Here's a potential solution. The following method searches for any subsequence of an array with repeats, and returns the range of the repeated values if there are three or more of them.
def find_3_or_more(ary)
ary.each_index do |i|
j = i + 1
while j < ary.length && ary[i] == ary[j]
j += 1
end
return (i...j) if j - i > 2
end
nil
end
This portion breaks the target string into an array of chars, and repeatedly slices out the characters in ranges identified as repeats until there are none, as indicated by a nil range.
def delete_3_or_more(str)
ary = str.chars
while r = find_3_or_more(ary)
ary.slice!(r)
end
return ary.join
end
It seems to do the job for your test cases.
def recursively_remove_runs_of_3_or_more(str)
arr = str.chars
loop do
a = arr.slice_when { |a,b| a.downcase != b.downcase }.to_a
b = a.reject! { |e| e.size > 2 }
arr = a.flatten
break arr.join if b.nil?
end
end
recursively_remove_runs_of_3_or_more "abbbaaccada"
#=> "ccada"
This uses Enumerable#slice_when (new in MRI v2.2). Note that Array#reject! returns nil when no changes are made.
You could alternatively use Enumerable#chunk_while (new in MRI v2.3). Simply replace:
a = arr.slice_when { |a,b| a.downcase != b.downcase }.to_a
with:
a = arr.chunk_while { |a,b| a.downcase == b.downcase }.to_a
chunk_while and slice_when are yin and yang.
If a regular expression could be used and case where not an issue, you could write:
str = "abbbaaccada"
s = str.dup
loop { break(s) if s.gsub!(/(.)\1{2,}/, '').nil? }
#=> "ccada"
(I wanted to comment, but it doesn't allow me to do that yet.)
Assuming that you are trying to learn, I chose to only give you some tips while avoiding a solution.
There might be shorter ways of doing this using regex or/and some String methods. However, you said you can not use regex.
My tip is, try to solve it only using the sections you have covered so far. It may not necessarily be the most elegant solution, but you can revise it as you progress. As others suggested, recursion might be a good option. But, if you are not familiar with that yet, you can try slicing the string and merging the parts you need. This can be combined with an endless loop to check the new string satisfies your condition: but think about when you need to break out of the loop.
Also, in your code:
v * (count - i)
String#* actually gives you count - i copies of v, concatenated together.

Perfect numbers array in one expression

I'm trying write a script that will print an array of perfect numbers. The hard part is that I have to do this only in one expression (line).
I searched ruby-doc for some useful methods but I didn't find anything about perfect numbers, so I only managed to do this using two functions:
def is_perf(n)
n == (1...n).select {|i| n % i == 0}.inject(:+)
end
def perfects(range)
(array = (2..range).to_a).each{|p|array.delete_if{|x| is_perf(x)==false }}
end
Can somebody help me squeeze this in just one line ?
For example like this:
(2..1000).select { |p| p == (1...p).select {|i| p % i == 0}.inject(:+) }
=> [6, 28, 496]
Edit: slightly shorter version, as suggested by #steenslag.

iterate array combination method with .any method

Is there anyway to iterate through different combinations of arrays?
I'm writing a program that returns true if the largest number in an array can be the sum of any of the members of the array.
This is my code: (forgive me, i learned how to program 2 weeks ago for the first time)
def ArrayAdditionI(arr)
arr=arr.sort
largest=arr.pop
n=arr.length
for i in 1..n
if arr.combination(i).to_a.any? {|array| array.inject(:+)==largest}
return true
else
return false
end
end
end
i tested it for
a = [1,2,3,4]
and it returned false even though clearly, 3+1 = 4.
When I change the above code from arr.combination(i) to arr.combination(2) its returns true. So I'm guessing it has something to do with the combination method not being able to be looped. Any suggestions?
You have return false in the wrong place. As it is, false is returned is there is no combination of one element (i.e., one element other than the one you've removed after sorting) that sums (i.e., is equal to) largest. Rather you want to return false only if no combination of any size sums to largest. This is what you need:
def max_match?(arr)
arr=arr.sort
largest=arr.pop
n=arr.length
for i in 1..n
return true if arr.combination(i).any? {|array|
array.inject(:+)==largest}
end
false
end
arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false
A few notes:
lower case letters and optional underscores are used for names of methods. You can also put a question (?) or explanation (!) mark at the end. Here a question mark seems appropriate.
to_a is not needed. Enumerable methods (e.g., any?) can have Enumerators as receivers.
sorting is expensive and unnecessary. Instead, just get the max value and remove it from the array. (Aside: you didn't say what happens if the maximum value appears more than once. See the code below and the last sentence.)
you don't need n=arr.length. for i in 1..arr.length is enough, except...
for ... is rarely used. Rubyists tend to use each instead, or one of the many methods from the Enumerable (mix-in) module (all of which invoke each).
you don't need return false because Ruby returns the value of the last statement evaluated, which is false if the method does not return true earlier.
Here's a more Ruby-like way to do that:
def max_match?(arr)
mx = arr.max
whats_left = arr - [mx]
(1..whats_left.size).any? {|n| whats_left.combination(n).any? {|c|
c.reduce(:+) == mx }}
end
arr = [1,4,7,3,5,2,13]
max_match?(arr) #=> true
arr = [1,3,4,7,59]
max_match?(arr) #=> false
If you wish this to return true when arr contains more than one value equal to mx, insert the following after mx = arr.max:
return true if arr.count(mx) > 1

Why does .all? return true on an empty array?

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}

Ruby array equality

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

Resources