getting differences between values in an array - ruby

I want to write an Array method in ruby that takes the successive values in the array and returns their differences as a new array (unshifting a '0' in at the beginning).
So feeding the array [4,7,11,16] into the method returns a new array [4,3,4,5].
1) does such a method already exist?
If not, then I think I know how to write it. However,
2) does a method already exist which allows me to test the input array and make sure it only consists of integers and/or floats?
Again, if not, I think I know how to write one.

p [4,7,11,16].unshift(0).each_cons(2).map{|a,b| b-a} # => [4, 3, 4, 5]

Keep it simple:
arr = [4,7,11,16]
last = 0
arr.map { |e| new=e-last; last=e; new }
#=> [4, 3, 4, 5]
Another way:
a = [arr.first]
enum = arr.each
loop do
a << -enum.next + enum.peek
end
a
#=> [4, 3, 4, 5]
Enumerator#peek raises a StopIteration exception when enum is at its last element. Kernel#loop handles the exception by breaking from the loop.

Regarding the first method, I am not aware of any such method in the Ruby Array class.
Regarding the second one, you can do it as explained in this answer:
your_array.all? {|i| i.is_a? Numeric }

Related

Reassign entire array to the same reference

I've searched extensively but sadly couldn't find a solution to this surely often-asked question.
In Perl I can reassign an entire array within a function and have my changes reflected outside the function:
#!/usr/bin/perl -w
use v5.20;
use Data::Dumper;
sub foo {
my ($ref) = #_;
#$ref = (3, 4, 5);
}
my $ref = [1, 2];
foo($ref);
say Dumper $ref; # prints [3, 4, 5]
Now I'm trying to learn Ruby and have written a function where I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items:
def filterItems(items)
removed, items = items.partition { ... }
After running the function, items returns to its state before calling the function. How should I approach this please?
I'd like to change an array items in-place by filtering out elements matching a condition and returning the removed items [...] How should I approach this please?
You could replace the array content within your method:
def filter_items(items)
removed, kept = items.partition { |i| i.odd? }
items.replace(kept)
removed
end
ary = [1, 2, 3, 4, 5]
filter_items(ary)
#=> [1, 3, 5]
ary
#=> [2, 4]
I would search for pass by value/reference in ruby. Here is one I found first https://mixandgo.com/learn/is-ruby-pass-by-reference-or-pass-by-value.
You pass reference value of items to the function, not the reference to items. Variable items is defined out of method scope and always refers to same value, unless you reassign it in the variable scope.
Also filterItems is not ruby style, see https://rubystyle.guide/
TL;DR
To access or modify an outer variable within a block, declare the variable outside the block. To access a variable outside of a method, store it in an instance or class variable. There's a lot more to it than that, but this covers the use case in your original post.
Explanation and Examples
In Ruby, you have scope gates and closures. In particular, methods and blocks represent scope gates, but there are certainly ways (both routine and meta) for accessing variables outside of your local scope.
In a class, this is usually handled by instance variables. So, as a simple example of String#parition (because it's easier to explain than Enumerable#partition on an Array):
def filter items, separator
head, sep, tail = items.partition separator
#items = tail
end
filter "foobarbaz", "bar"
#=> "baz"
#items
#=> "baz"
Inside a class or within irb, this will modify whatever's passed and then assign it to the instance variable outside the method.
Partitioning Arrays Instead of Strings
If you really don't want to pass things as arguments, or if #items should be an Array, then you can certainly do that too. However, Arrays behave differently, so I'm not sure what you really expect Array#partition (which is inherited from Enumerable) to yield. This works, using Enumerable#slice_after:
class Filter
def initialize
#items = []
end
def filter_array items, separator
#items = [3,4,5].slice_after { |i| i == separator }.to_a.pop
end
end
f = Filter.new
f.filter_array [3, 4, 5], 4
#=> [5]
Look into the Array class for any method which mutates the object, for example all the method with a bang or methods that insert elements.
Here is an Array#push:
ary = [1,2,3,4,5]
def foo(ary)
ary.push *[6, 7]
end
foo(ary)
ary
#=> [1, 2, 3, 4, 5, 6, 7]
Here is an Array#insert:
ary = [1,2,3,4,5]
def baz(ary)
ary.insert(2, 10, 20)
end
baz(ary)
ary
#=> [1, 2, 10, 20, 3, 4, 5]
Here is an example with a bang Array#reject!:
ary = [1,2,3,4,5]
def zoo(ary)
ary.reject!(&:even?)
end
zoo(ary)
ary
#=> [1, 3, 5]
Another with a bang Array#map!:
ary = [1,2,3,4,5]
def bar(ary)
ary.map! { |e| e**2 }
end
bar(ary)
ary
#=> [1, 4, 9, 16, 25]

We have 'index' and 'rindex', we have 'find' but no 'rfind'

When applied to an Array, index (invoked with a block) returns the index of the first element satisfying the condition, and rindex returns the index of the last one. Similarly, we have find to return the element itself. However, there is no corresponding rfind that would return the last element of an array satisfying a condition.
Does Ruby already have a method that accomplishes this?
Before monkey-patching the Array class, I want to make sure.
You can do it like this:
enum = [1, 2, 3, 4].reverse_each
# => #<Enumerator: [1, 2, 3, 4]:reverse_each>
enum.find(&:odd?)
# => 3
Notice that, unlike using Array#reverse, it does not create a temporal array that is thrown out immediately.
Doing it at once:
[1, 2, 3, 4].reverse_each.find(&:odd?)
# => 3
In other words, we have reverse_each.find instead of rfind; not a big deal.

Access `self` of an object through the parameters

Let's say I want to access an element of an array at a random index this way:
[1, 2, 3, 4].at(rand(4))
Is there a way to pass the size of the array like the following?
[1, 2, 3, 4].at(rand(le_object.self.size))
Why would I do that?--A great man once said:
Science isn't about why, it is about why not.
Not recommended, but instance_eval would somehow work:
[1, 2, 3, 4].instance_eval { at(rand(size)) }
And you can also break out of tap:
[1, 2, 3, 4].tap { |a| break a.at(rand(a.size)) }
There's an open feature request to add a method that yields self and returns the block's result. If that makes it into Ruby, you could write:
[1, 2, 3, 4].insert_method_name_here { |a| a.at(rand(a.size)) }
No, you can't do that. Receiver of a method (that array) is not accessible by some special name at the call site. Your best bet is assigning a name to that object.
ary = [1, 2, 3, 4]
ary.at(rand(ary.size))
Of course, if all you need is a random element, then .sample should be used. Which does not require evaluation of any arguments at the call site and its self is the array.
You can use instance_eval to execute ruby code with the binding of the array variable
[1, 2, 3, 4].instance_eval { at(rand(size)) }
Assuming you are interested in a random element as Array#at returns an element at given index, you can use Array#sample to pick a random element from an array.
[1,2,3,4].sample
#=> 3
If you do not want to use instance_eval (or any form of eval), then, you can add a method to Array class by monkey patching - generally speaking, I am not sure whether it's a wise idea to monkey patch though
class Array
def random_index
rand(size)
end
end
["a","b","c","d"].random_index
#=> 2
You could do something similar with lambda:
getrand = ->(x) { x[rand(x.count)] }
getrand.call [1,2,3]
# => 2

How to #rewind the internal position under #each?

I'm trying to write a code where the enumeration sequence is rewinded to the beginning.
I think rewind is appropriate for this application, but I'm not sure how to implement it under an each iterator passing to a block? In the Ruby-Docs example, next is used to move the internal position by one at a time. With a block, it would move autonomously.
There's not many good examples online for this specifically. My workaround at the moment is to nest an iterator under a loop and using break under the iterator. When the iterator breaks, the loop resets the enumeration sequence.
Is there a better way—as I'm sure there is—of doing this?
Use the Enumerator#rewind method from Ruby core class libarary.
Rewinds the enumeration sequence to the beginning.If the enclosed object responds to a “rewind” method, it is called.
a = [1,2,3,4]
enum= a.each
enum # => #<Enumerator: [1, 2, 3, 4]:each>
enum.next # => 1
enum.next # => 2
enum.rewind # => #<Enumerator: [1, 2, 3, 4]:each>
enum.next # => 1

Getting value of three consecutive elements in array

I have a large array, h, that contains several instances of a parameter called startingParam, which is always followed by two other parameters that are related but not always the same. I need to look for every instance of startingParam in the array, and push it and the next two parameters into a separate array, holdingArray.
The following code is not working, due to the fact that I am very new to Ruby. Does anybody know what I am doing wrong? Is there a better way to approach the problem?
h.each do |param|
if param == 'startingParam'
holdingArray << h.[param],
holdingArray << h.[param + 1],
holdingArray << h.[param + 2]
end
end
Thanks so much.
You can grab the chunks using #slice_before:
arr = ['startingParam', 1, 2, 'startingParam', 3, 4]
arr.slice_before('startingParam')
# => [['startingParam', 1, 2], ['startingParam', 3, 4]]
If you created the original data structure, you may want to re-consider your design, however.
Functional approach:
>> ary = ['hello', 'startingParam', 1, 2, 'xyz', 'startingParam', 3, 4, 'bye']
>> ary.each_cons(3).select { |v, *vs| v == "startingParam" }.flatten(1)
=> ["startingParam", 1, 2, "startingParam", 3, 4]
So there are a few problems. For starters, you can't subscript arrays by doing h.[anything], and you are also subscripting based on the value (and not the index). You are also checking to see if the parameter matches the literal string "starting_param" and not its value. So what I expect you want is the following:
h.each_with_index do |param, index|
if param == startingParam
holdingArray << h[index]
holdingArray << h[index+1]
holdingArray << h[index+2]
end
end
You'll also note that if the item is in the last two slots of the array, this will wrap around and grab items from the beginning of the array (due to how Ruby handles array subscripts being out of bounds).
You could also use the range slicing operation (I've changed the varnames slightly since camelcasing is bad style in ruby)
h.each_with_index do |param, index|
if param == starting_param
holding_array.push(h[index..index+2])
end
end

Resources