Testing array elements vs multiple criteria - ruby

I am trying to create a method complex_check(n), which will do the following:
Create an array of integers ascending from 0 to n
Check each element of that array against complex criteria.
For example, I have an array from 0..n, and I want to know which elements of the array are both evenly divisible by 3 and not divisible by 4. I can index through to check for single criteria like odd?, etc., but is there a compact way to check each integer against multiple criteria?

This is the best I could come up with, I think this is sort of what you're trying to do:
def complex_check(n)
check_array = (0..n).to_a
check_array.select { |num|
num % 3 == 0 &&
num % 4 != 0
}
end
Then using it:
complex_check(15)
=> [3, 6, 9, 15]

One of the things Ruby is very good at is processing through lists and other regular data structures. The Enumerable extensions common to many things including Array allow you to quickly filter, split, chunk, and otherwise completely rework the data you're dealing with. Often a few quick alterations can do the job.
In this case select can be used to filter out undesirable values from your potential candidates in the range 0 to n:
def complex_check(n)
(0..n).select do |v|
v % 3 == 0 and v % 4 != 0
end
end
The key here is using select where any block that returns a logically true value will be a signal to include the element, and otherwise to exclude it. The opposite of this is reject which works on the same principle, just with inverted logic.
You could also pass these filters in dynamically:
def complex_check(n, *tests)
tests.each_with_object((0..n).to_a) do |test, a|
a.select!(&test)
end
end
Where your test code ends up looking like this:
complex_check(
50,
-> (v) { v % 3 == 0 },
-> (v) { v % 4 != 0 }
)
Then you can plug in tests using lambdas which are little reusable blocks.

create an array of integers ascending from 0 to n
Don't do this if you don't have to, which is almost never.
Use a Range or an Enumerator. They are real easy:
0.upto(n).select do |i| #0.upto(n) results in a Enumerator
#complex criteria
end
#or
def complex_check(n)
0.step(n,3).reject{|n| (n%4).zero?} #0.step(n,3) is an Enumerator
end
p complex_check(15) #= [3, 6, 9, 15]

Related

Ruby - How to write a method that returns an array of strings?

I've tried different ways and this is probably the closest that I got to it. I am trying to write a method that takes in an array of strings and returns it containing the strings that are at least 5 characters long and end with "y".
I'm a beginner and this is my second problem I've come across with, and I've tried multiple if statements and using a while loop, however I could not get to it and now this is where I am at. Thank you!
def phrases(arr1, arr2)
arr1 = ["funny", "tidy", "fish", "foogiliously"]
arr2 = ["happily", "lovely", "hello", "multivitaminly"]
if (arr1.length > 5 && arr1.length == "y")
return arr1
elsif (arr2.length > 5 && arr2.length == "y")
return arr2
end
end
puts phrases(["funny", "tidy", "fish", "foogiliously"])
puts phrases(["happily", "lovely", "hello", "multivitaminly"])
If I'm understanding your question correctly, you want to return a subset of the passed in array matching your conditions (length ≥ 5 and last character = 'y'). In that case:
def phrases(words)
words.grep(/.{4}y\z/)
end
What that regex does:
.{4} means 4 of any character
y is the letter y
\z is the end of the string, so we don't match in the middle of a long word
The docs for Enumerable#select are here (an Array is an Enumerable).
Output:
> phrases(["funny", "tidy", "fish", "foogiliously"])
=> ["funny", "foogiliously"]
> phrases(["happily", "lovely", "hello", "multivitaminly"])
=> ["happily", "lovely", "multivitaminly"]
If you only want word characters, rather than any character, you'd use this regex instead: /\A.{4,}y\z/. In that case, \A means the start of the string, and \w{4,} means at least 4 word characters.
If, when given an array and inclusion criterion, one wishes to construct an array that contains those elements of the first array that satisfy the inclusion criterion, one generally uses the method Array#select or Array#reject, whichever is more more convenient.
Suppose arr is a variable that holds the given array and include_element? is a method that takes one argument, an element of arr, and returns true or false, depending on whether the inclusion criterion is satisified for that element. For example, say the array comprises the integers 1 through 6 and the inclusion criterion is that the number is even (2, 4 and 6). We could write:
arr = [1,2,3,4,5,6]
def include_element?(e)
e.even?
end
include_element?(2)
#=> true
include_element?(3)
#=> false
arr.select { |e| include_element?(e) }
#=> [2, 4, 6]
The method include_element? is so short we probably would substitute it out and just write:
arr.select { |e| e.even? }
Array#select passes each element of its receiver, arr, to select's block, assigns the block variable e to that value and evaluates the expression in the block (which could be many lines, of course). Here that expresssion is just e.even?, which returns true or false. (See Integer#even? and Integer#odd?.)
If that expression evaluates as a truthy value, the element e is to be included in the array that is returned; if it evaluates as a falsy value, e is not to be included. Falsy values (logical false) are nil and false; truthy values (logical true) are all other Ruby objects, which of course includes true.
Notice that we could instead write:
arr.reject { |e| e.odd? }
Sometimes the inclusion criterion consists of a compound expression. For example, suppose the inclusion criterion were to keep elements of arr that are both even numbers and are at least 4. We would write:
arr.select { |e| e.even? && e >= 4 }
#=> [4, 6]
With other criteria we might write:
arr.select { |e| e.even? || e >= 4 }
#=> [2, 4, 5, 6]
or
arr.select { |e| e < 2 || (e > 3 && e < 6) }
#=> [1, 4, 5]
&& (logical 'and') and || (logical 'or') are operators (search "operator expressions"). As explained at the link, most Ruby operators are actually methods, but these two are among a few that are not.
Your problem now reduces to the following:
arr.select { |str| <length of str is at least 5> && <last character of str is 'y'> }
You should be able to supply code for the <...> bits.
You are trying to write a function that should work on a single array at a time I think. Also, you are taking in an array, and retaining only those elements that satisfy your conditions: at least 5 characters long, and ends with y. This is a filtering operation. Read about the methods available for ruby's Array class here
def phrases(array)
...
filtered_array
end
Now the condition you are using is this arr1.length > 5 && arr1.length == "y".
The first half should check if the string length is greater than 5, not the array length itself. The second half is an indexing operation, and your code for that is incorrect. basically you are checking if the last character in the string is y.
Usually strings are indexed in this manner: string[index]. In your case you can use string[-1]=='y' or string[string.length - 1]=='y'. This because arrays and strings are zero indexed in ruby. The first element has index of 0, the second has an index of 1, and the last one, therefore, will have an index of length-1. If you use negative indexes then the array is indexed from the end, so string[-1] is a quick way to get to the last element.
Considering this, the function will take the following structure:
def phrases(array)
filtered_array = [] # an empty array
loop through the input array
for each element check for the condition element.length > 5 && element[-1]=='y'
if true: push the element into the filtered_array
once the loop is done, return the filtered array
end
Read about ruby arrays, the methods push, filter and select in the above linked documentation to get a better idea. I'd also recommend the codeacademy ruby tutorial.
Edit: Both halves of the condition are incorrect. I had overlooked a mistake in my earlier answer. arr1.length refers to the length of the array. You want to check the length of each string in the array. So in your for loop you should check the length of the loop variable, if that is greater than 5.
You may want to spend some time reading about the methods in the core library, especially String#end_with? and Enumerable#select. You could then write a method that'd contain something like this:
['abc', 'qwerty', 'asdfghjk', 'y'].select{|s| s.length >= 5}.select{|s| s.end_with? 'y'}
#=> ["qwerty"]

Please walk me through this code from ruby monk

def random_select(array, n)
result = []
n.times do
# I do not fully understand how this line below works or why. Thank you
result.push array[rand(array.length)]
end
result
end
You are probably confused by this part:
n.times do
result.push(array[rand(array.length)])
end
n.times says it should loop n times.
result.push says to basically "push" or "put" something in the array. For example:
a = []
a.push(1)
p a #=> [1]
In array[rand(array.length)] , rand(array.length) will produce a random number as an index for the array. Why? rand(n) produces a number from 0 to n-1. rand(5) will produce either 0,1,2,3 or 4, for example.
Arrays use 0-based indexing, so if you have an array, say a = ['x', 'y', 'z'], to access 'x' you do a[0], to access y you do a[1] and so on. If you want to access a random element from a, you do a[rand(array.length)], because a.length in this case is 3, and rand(3) will produce a number that is either 0, 1 or 2. 0 is the smallest index and 2 is the largest index of our example array.
So suppose we call this method:
random_select([6,3,1,4], 2)
Try to see this code from the inside out. When the code reaches this part:
result.push(array[rand(array.length)])
it will first execute array.length which will produce 4. It will then execute rand(array.length) or rand(4) which will get a number between 0 and 3. Then, it will execute array[rand(array.length)] or array(some_random_number_between_0_and_3) which will get you a random element from the array. Finally, result.push(all_of_that_code_inside_that_got_us_a_random_array_element) will put the random element from the array in the method (in our example, it will be either 6, 3, 1 or 4) in the results array. Then it will repeat this same process once again (remember, we told it to go 2 times through the iteration).
The code can be rewritten to be much simpler, using the block-form Array constructor:
def random_select(array, n)
Array.new(n) {array.sample}
end
This creates a new array of size n and fills it with random samples from the array.
Note that the above solution, like your sample code, selects from the entire array each time which allows duplicate selections. If you don't want any duplicate selections, it's even simpler, since it is the default behavior of Array#sample:
def random_select(array, n)
array.sample(n)
end

Check if the sum of two different numbers in an array equal a variable number?

In Ruby, I would like to take an array of numbers, select 2 different numbers, add those 2 numbers together and see weather there equal to a variable x.y'd a variable x. Here is the code I used
def arrayIsEqual? (numArray, x)
return true if numArray.sample + numArray.sample == x
return false if numArray.empty? || numArray.count == 1
end
for example
numArray = [4,2,7,5]
x = 11
arrayIsEqual (numArray, n) should return true, since 4 + 7 = n(11)
How do I get this to work?
I don't want it to be 2 random numbers, just any 2 different numbers that add up to n
It looks like you're trying to see if there are any two numbers in the array that add up to the specified value x. However, your code just picks two numbers at random and checks if those numbers add up.
Ruby has the Array#combination method, which generates all combinations of a given length:
def contains_pair_for_sum?(arr, n)
!!arr.uniq.combination(2).detect { |a, b| a + b == n }
end
A few things to note:
First, we named it according to Ruby conventions: each word is separated_by_underscores. The ? on the end means that the method is a predicate method and returns a true or false value.
Inside the method, a few things happen. Let's look at that line, piece by piece.
arr: We take the array that was passed in.
<...>.uniq: We only look at the unique elements (because the OP wants to pick two different numbers).
<...>.combination(2): We ask for all combinations from the array of length 2. If the array was [4, 5, 6], we'd get [[4, 5], [4, 6], [5, 6]].
<...>.detect { |a, b| a + b == n }: We look for the first combination that adds up to n. If we found one, that's the result of that method. Otherwise, we get nil.
!!<...>: Finally, we take the result we got from detect and negate it twice. The first negation produces a Boolean value (true if the value we got was nil, or false if it's anything else); the second negation produces a Boolean value that's identical to the truth value of the first negation. This is a Ruby idiom to coerce a result into being either true or false.
Let's see it in action:
array = [4, 5, 9, 7, 8]
contains_pair_for_sum?(array, 11)
# => true (because [4, 7] sums to 11)
contains_pair_for_sum?(array, 17)
# => true (because [9, 8] sums to 17)
contains_pair_for_sum?(array, 100)
# => false (no pair matched)
I understand that your question is "is there any pair of numbers in my array equals x", in which case this will do what you need:
def has_pair_equal?(num_array, x)
(0..num_array.length-1).any? do |i|
num_array[i+1..-1].any? { |n| n + num_array[i] == x }
end
end
This checks all sums of pairs of numbers in the array, and checks if their sum is x. sample randomly picks an item from the array, which means that what your code does is "return true sometimes if there is a pair of numbers in my array equals x"
def array_is_equal? (num_array, x)
equality = 0
num_array.each do |a|
equality += 1 if a == x
return true if equality == 2
end
return false
end
Use lowercase and underscores for variables in Ruby. The convention is different here than in some other languages.
One liner
x=[4,2,7,5]; x.each_with_index.any? {|y,i| x.each_with_index.any? {|z,j| unless i==j; z+y==11; end } }
And as a function
def pair_sum_match?(arr, x)
arr.each_with_index.any? do |y,i|
arr.each_with_index.any? do |z,j|
unless i==j
z+y==x
end
end
end
end
Updated: Added each_with_index to avoid self inclusion on checks. It's a lot longer now :-/
Just iterate over it once and use the target number to see if it matches. 100 times faster then most of the answers here
numbers = ( -10..10 ).to_a
numbers.unshift( numbers.first + -1 ) # if you do -20 or 20
numbers.push( numbers.last + 1 )
target = 5
searched = { }
matches = { }
numbers.each do |number|
if searched[ target - number + 1 ] == true
matches[ "#{ number }_plus_#{ target - number }" ] = target
end
searched[ number + 1 ] = true
end
ap matches

Ruby: how to know depth of multidemensional array

This is my problem I have met in my assignment.
Array A has two elements: array B and array C.
Array B has two elements: array D and array E
At some point, array X just contains two elements: string a and string b.
I don't know how to determine how deep array A is. For example:
arrA = [
[
[1,2]
]
]
I have tested by: A[0][0][0] == nil which returns false. Moreover, A[0][0]..[0] == nil always returns false. So, I cannot do this way to know how deep array A is.
If this is not what you're looking for, it should be a good starting point:
def depth (a)
return 0 unless a.is_a?(Array)
return 1 + depth(a[0])
end
> depth(arrA)
=> 3
Please note that this only measures the depth of the first branch.
My solution which goes below answers the maximum depth of any array:
Example: for arr=[ [[1],[2,3]], [[[ 3,4 ]]] ], the maximum depth of arr is 4 for 3,4.
Aprroach - flatten by one level and compare
b, depth = arr.dup, 1
until b==arr.flatten
depth+=1
b=b.flatten(1)
end
puts "Array depth: #{depth}" #=> 4
Hope it answers your question.
A simple pure functional recursive solution:
def depth(xs, n=0)
return case
when xs.class != Array
n
when xs == []
n + 1
else
xs.collect{|x| depth x, n+1}.max
end
end
Examples:
depth([]) == 1
depth([['a']])) == 2
depth([1, 2, 3, 4, [1, 2, 3, [[2, 2],[]], 4, 5, 6, 7], 5, 5, [[[[[3, 4]]]]], [[[[[[[[[1, 2]]]]]]]]]]) == 10
Here's a one-liner similar to kiddorails' solution extracted into a method:
def depth(array)
array.to_a == array.flatten(1) ? 1 : depth(array.flatten(1)) + 1
end
It will flatten the array 1 dimension at the time until it can't flatten anymore, while counting the dimensions.
Why is this better than other solutions out there?
doesn't require modification to native classes (avoid that if possible)
doesn't use metaprogramming (is_a?, send, respond_to?, etc.)
fairly easy to read
works on hashes as well (notice array.to_a)
actually works (unlike only checking the first branch, and other silly stuff)
Also one line code if you want to use
def depth (a)
a.to_s.count("[")
end

Working with arbitrary inequalities and checking which, if any, are satisfied

Given a non-negative integer n and an arbitrary set of inequalities that are user-defined (in say an external text file), I want to determine whether n satisfies any inequality, and if so, which one(s).
Here is a points list.
n = 0: 1
n < 5: 5
n = 5: 10
If you draw a number n that's equal to 5, you get 10 points.
If n less than 5, you get 5 points.
If n is 0, you get 1 point.
The stuff left of the colon is the "condition", while the stuff on the right is the "value".
All entries will be of the form:
n1 op n2: val
In this system, equality takes precedence over inequality, so the order that they appear in will not matter in the end. The inputs are non-negative integers, though intermediary and results may not be non-negative. The results may not even be numbers (eg: could be strings). I have designed it so that will only accept the most basic inequalities, to make it easier for writing a parser (and to see whether this idea is feasible)
My program has two components:
a parser that will read structured input and build a data structure to store the conditions and their associated results.
a function that will take an argument (a non-negative integer) and return the result (or, as in the example, the number of points I receive)
If the list was hardcoded, that is an easy task: just use a case-when or if-else block and I'm done. But the problem isn't as easy as that.
Recall the list at the top. It can contain an arbitrary number of (in)equalities. Perhaps there's only 3 like above. Maybe there are none, or maybe there are 10, 20, 50, or even 1000000. Essentially, you can have m inequalities, for m >= 0
Given a number n and a data structure containing an arbitrary number of conditions and results, I want to be able to determine whether it satisfies any of the conditions and return the associated value. So as with the example above, if I pass in 5, the function will return 10.
They condition/value pairs are not unique in their raw form. You may have multiple instances of the same (in)equality but with different values. eg:
n = 0: 10
n = 0: 1000
n > 0: n
Notice the last entry: if n is greater than 0, then it is just whatever you got.
If multiple inequalities are satisfied (eg: n > 5, n > 6, n > 7), all of them should be returned. If that is not possible to do efficiently, I can return just the first one that satisfied it and ignore the rest. But I would like to be able to retrieve the entire list.
I've been thinking about this for a while and I'm thinking I should use two hash tables: the first one will store the equalities, while the second will store the inequalities.
Equality is easy enough to handle: Just grab the condition as a key and have a list of values. Then I can quickly check whether n is in the hash and grab the appropriate value.
However, for inequality, I am not sure how it will work. Does anyone have any ideas how I can solve this problem in as little computational steps as possible? It's clear that I can easily accomplish this in O(n) time: just run it through each (in)equality one by one. But what happens if this checking is done in real-time? (eg: updated constantly)
For example, it is pretty clear that if I have 100 inequalities and 99 of them check for values > 100 while the other one checks for value <= 100, I shouldn't have to bother checking those 99 inequalities when I pass in 47.
You may use any data structure to store the data. The parser itself is not included in the calculation because that will be pre-processed and only needs to be done once, but if it may be problematic if it takes too long to parse the data.
Since I am using Ruby, I likely have more flexible options when it comes to "messing around" with the data and how it will be interpreted.
class RuleSet
Rule = Struct.new(:op1,:op,:op2,:result) do
def <=>(r2)
# Op of "=" sorts before others
[op=="=" ? 0 : 1, op2.to_i] <=> [r2.op=="=" ? 0 : 1, r2.op2.to_i]
end
def matches(n)
#op2i ||= op2.to_i
case op
when "=" then n == #op2i
when "<" then n < #op2i
when ">" then n > #op2i
end
end
end
def initialize(text)
#rules = text.each_line.map do |line|
Rule.new *line.split(/[\s:]+/)
end.sort
end
def value_for( n )
if rule = #rules.find{ |r| r.matches(n) }
rule.result=="n" ? n : rule.result.to_i
end
end
end
set = RuleSet.new( DATA.read )
-1.upto(8) do |n|
puts "%2i => %s" % [ n, set.value_for(n).inspect ]
end
#=> -1 => 5
#=> 0 => 1
#=> 1 => 5
#=> 2 => 5
#=> 3 => 5
#=> 4 => 5
#=> 5 => 10
#=> 6 => nil
#=> 7 => 7
#=> 8 => nil
__END__
n = 0: 1
n < 5: 5
n = 5: 10
n = 7: n
I would parse the input lines and separate them into predicate/result pairs and build a hash of callable procedures (using eval - oh noes!). The "check" function can iterate through each predicate and return the associated result when one is true:
class PointChecker
def initialize(input)
#predicates = Hash[input.split(/\r?\n/).map do |line|
parts = line.split(/\s*:\s*/)
[Proc.new {|n| eval(parts[0].sub(/=/,'=='))}, parts[1].to_i]
end]
end
def check(n)
#predicates.map { |p,r| [p.call(n) ? r : nil] }.compact
end
end
Here is sample usage:
p = PointChecker.new <<__HERE__
n = 0: 1
n = 1: 2
n < 5: 5
n = 5: 10
__HERE__
p.check(0) # => [1, 5]
p.check(1) # => [2, 5]
p.check(2) # => [5]
p.check(5) # => [10]
p.check(6) # => []
Of course, there are many issues with this implementation. I'm just offering a proof-of-concept. Depending on the scope of your application you might want to build a proper parser and runtime (instead of using eval), handle input more generally/gracefully, etc.
I'm not spending a lot of time on your problem, but here's my quick thought:
Since the points list is always in the format n1 op n2: val, I'd just model the points as an array of hashes.
So first step is to parse the input point list into the data structure, an array of hashes.
Each hash would have values n1, op, n2, value
Then, for each data input you run through all of the hashes (all of the points) and handle each (determining if it matches to the input data or not).
Some tricks of the trade
Spend time in your parser handling bad input. Eg
n < = 1000 # no colon
n < : 1000 # missing n2
x < 2 : 10 # n1, n2 and val are either number or "n"
n # too short, missing :, n2, val
n < 1 : 10x # val is not a number and is not "n"
etc
Also politely handle non-numeric input data
Added
Re: n1 doesn't matter. Be careful, this could be a trick. Why wouldn't
5 < n : 30
be a valid points list item?
Re: multiple arrays of hashes, one array per operator, one hash per point list item -- sure that's fine. Since each op is handled in a specific way, handling the operators one by one is fine. But....ordering then becomes an issue:
Since you want multiple results returned from multiple matching point list items, you need to maintain the overall order of them. Thus I think one array of all the point lists would be the easiest way to do this.

Resources