Why does Range#select produce an Array object? - arrays

Consider I have a Range object,
(1..30).class # => Range
Now consider I am trying to find the factors of num,
num = 30
factors = (1..num).select { |n| num % n == 0 }
factors.class # => Array
For Ruby 2.3.1 a Range object does not have #select, but an Array object does. How is calling Range#select producing an Array object?
I believe that I am not fully understanding the Ruby Object Model. My current understanding is that factors.class.eql? Range should return true, not false.
factors.class.eql? Array # => true

The object model in Ruby is simple, single inheritance but with ability to "mixin" modules to add shared behavior. In your case you are using the select method which exists in the module Enumerable. This module is mixed into Array, Hash, and Range. This gives instances of those classes methods such as select. You can read more about enumerable methods here: https://ruby-doc.org/core-2.2.3/Enumerable.html#method-i-select
If you think about it, it makes sense that Range#select returns an Array. You're not selecting contiguous values from the range are you? You're selecting arbitrary values from which the block returns true, this makes it impossible to return a range therefore, #select will always return an array even if it's called on a Hash or any other Class that mixes in Enumerable.
Update:
To understand how Enumerable is returning an Array from a Range
To implement any classes that mix in Enumerable you only have to define the #each method on your class. Say you hypothetically re-implemented Range:
class Range
include Enumerable # mixin
def initialize(first, last)
#number_range = first.upto last # this is an array of ints
end
def each(&block) # this methods returns an enumerable
#number_range.each &block
end
end
With the above we can initialize our hypothetical range instance:
#hypo_range = Range.new 1, 10
And call enumerable methods on it:
#hypo_range.any? { |i| i == 5 } # => true
#hypo_range.select &:odd? # => [1,3,5,7,9]
Because you need only implement #each to hook into the Enumerable API, Ruby knows exactly what to do with it no matter what the class of the object is. This is because in your new #each method you are iterating over an array already! Enumerable uses your each method under the hood to implement all the other enumerable methods on top e.g. any?, select, find, etc.
That #each method is where you tell Ruby how to iterate over your collection of objects. Once Ruby knows how to iterate over your objects the results are already an Array.
Rubinius implementation of Range
You can see here that Range is implemented by using while to loop from the first value until it reaches the last value and yielding to the block on each iteration. The block collects the results into an Array and that's how you get the Array out of calling Range#select because select is using that each under the hood.
https://github.com/rubinius/rubinius/blob/master/core/range.rb#L118
Some resources:
https://www.sitepoint.com/guide-ruby-collections-iii-enumerable-enumerator/
https://mauricio.github.io/2015/01/12/implementing-enumerable-in-ruby.html
http://practicingruby.com/articles/building-enumerable-and-enumerator

Check the docs for Range http://ruby-doc.org/core-2.3.1/Range.html
It says included modules Enumerable. And that's where there are implemented map, all?, any?, find, select, inject and many many more methods.

Related

How can I get my array to only be manipulated locally (within a function) in Ruby?

Why is my array globally manipulated, when I run the below ruby code? And how can I get arrays to be manipulated only within the function's scope?
a = [[1,0],[1,1]]
def hasRowsWithOnlyOnes(array)
array.map { |row|
return true if row.keep_if{|i| i != 1 } == []
}
false;
end
puts a.to_s
puts hasRowsWithOnlyOnes(a)
puts a.to_s
$ ruby test.rb output:
[[1, 0], [1, 1]]
true
[[0], []]
I can't get it to work. I've even tried .select{true} and assign it to a new name. How does the scope work in Ruby for Arrays?
Just for reference, $ ruby -v:
ruby 2.2.1p85 (2015-02-26 revision 49769) [x86_64-linux]
It's not a scope problem, it's an argument passing problem
All variables in Ruby are references to objects.
When you pass an object to a method, a copy of that object's reference is made and passed to the object.
That means that the variable array in your method and the top-level variable a refer to the exact same Array. Any changes made to array will be also visible as changes to a, since both variables refer to the same object.
Your method does modify the array by calling Array#keep_if. The keep_if method modifies the array in-place.
The fix
The best fix for this is to make it so that your method does not modify the array that was passed in. This can be done pretty neatly using the Enumerable#any? and Enumerable#all? methods:
def has_a_row_with_only_ones(array)
array.any? do |row|
row.all? { |e| e == 1 }
end
end
This code says that the method returns true if, for any row, every element in that row is 1. These methods do not modify the array. More important, they communicate the method's intent clearly.
The poor workaround
If you want the method to act as through a copy of the array were passed to it, so that the array can be modified without that modification being visible outside the method, then you can make a deep copy of the array. As shown in this answer, you can define this method to make a deep copy:
def deep_copy(o)
Marshal.load(Marshal.dump(o))
end
Then, at the top of the method, make the deep copy:
def has_a_row_with_only_ones(array)
array = deep_copy(array)
# code that modifies array
end
This should be avoided because it's slow.
Ruby is pass by value
Via sitepoint
Ruby has variables defined within different scopes, which you probably
know already. I found that most tutorials describe them briefly (the
variable types), but they fail to mention precisely what their scope
is.
Here are the details:
Class variable (##a_variable): Available from the class definition and any sub-classes. Not available from anywhere outside.
Instance variable (#a_variable): Available only within a specific object, across all methods in a class instance. Not available directly from class definitions.
Global variable ($a_variable): Available everywhere within your Ruby script.
Local variable (a_variable): It depends on the scope. You’ll be working with these most and thus encounter the most problems, because their scope depends on various things.

How to add and remove objects from an array in Eiffel

I am trying to make a CONTAINER class that maintains an array of CRITTER objects (that I have already created and tested. Note, there are various CRITTER subspecies, that are inheriting from the CRITTER super class). The aim is to add and remove CRITTER objects from this array. This is what the CONTAINER class looks like:
class
CONTAINER
create
make
feature
num: detachable INTEGER
list: ARRAY[CRITTER]
make
local
do
create list.make_empty
num := 0
end
addCritter(critter: CRITTER)
do
list.put(animal, num)
num := num + 1
end
removeCritter(critter: CRITTER)
do
list.put (list.at (num), ???) -- put last element in position of element to be removed
list.remove_tail (num) -- remove tail
num := num - 1
end
end
Two issues:
Firstly, I can instantiate the CONTAINER class inside APPLICATION, but when I call
create container.make
container.addCritter(myCritter)
I get a precondition, invalid index violation error on the second line. This may be because I have not set the upper and lower bounds of the array. However, when I try to do so, I get syntax errors. Which is the way to solve this issue?
Secondly, in order to remove an object from the array, it would help if I could get hold of the index value, but I can't see any function that does this, unless I am missing something.
ARRAYs are usually used for fixed-length containers. In your case, with lots of dynamic changes, it's better to use more dynamic structures, for example, ARRAYED_LIST. Similar to ARRAY it provides features to access items by their index, but there are also more convenient ones. New elements can be added by using feature extend. Old elements can be removed by using feature prune if only one element matching a given one needs to be removed, or prune_all, if all matching elements need to be removed. The word "matching" denotes either reference or object equality, depending on which comparison criteria is required: = or ~. The comparison criteria is changed using feature compare_objects.
Some general observations:
There is no need to track number of elements yourself, usually there is a feature count that provides this number.
Indexes in Eiffel usually start with 1, not 0.
The declaration detachable INTEGER is equivalent to INTEGER because INTEGER is expanded and all expanded types are attached regardless of any attachment marks.
The following discussion might also be useful:
How to initialise an array of objects in Eiffel?

How do I use .fill method to create new objects?

Specifically, I'm wondering why when I create a new array with several sub-arrays using .fill, the sub-arrays created using .fill are the same object.
array = Array.new.fill([], 0..8)
subsquare[0].object_id => 7220340
subsquare[1].object_id => 7220340
How would I create these sub-arrays while ensuring each sub-array was its own object?
The why to this question can be found if you look at Array.new:
http://ruby-doc.org/core-2.2.0/Array.html
Note that the second argument populates the array with references to
the same object. Therefore, it is only recommended in cases when you
need to instantiate arrays with natively immutable objects such as
Symbols, numbers, true or false.
To create an array with separate objects a block can be passed
instead. This method is safe to use with mutable objects such as
hashes, strings or other arrays
The workaround as specified in the doc is:
array = Array.new(8) { [] }

In order to preallocate memory in Matlab, I want to initialize my array of objects. How do I do this?

I have a class of objects known as blocks. Currently, I am creating an array of blocks using a for loop by simply tacking them unto an empty array
blockArray=[];
for ii=1:Size
blockArray=[blockArray block(....)];
end
In order to preallocate memory, how do I initialize an object array of blocks with dummy values?
For instance if instead of using block objects I used numbers, I could easily preallocate by using zeros(1,Size). Is there something similar that I could do?
The matlab documentation describes
To preallocate the object array, assign the last element of the array first. MATLAB® fills the first to penultimate array elements with default DocArrayExample objects.
So, to do this, instead of iterating over from 1:size, it is simpler to do...
blockArray = []
blockArray(size) = block(...)
The language does not really support this, there exists multiple solutions (or workarounds).
Replicating the first instance
When pushing the first element into the array, you can fill the whole array with this element to achieve a preallocation. This might look very bad, but it is actually the fastest possibility known to me.
for ii=1:S
%assumption e is a scalar, otherwise the code is totally screwed
e=block(....)
if ii==1
%to do preallocation, fill it with your first element
blockArray(1:S)=e
else
blockArray(ii)=e
end
end
Use cell arrays
Obvious simple solution, you can put any class into the fields
blockArray=cell(S,1);
for ii=1:S
%assumption e is a scalar, otherwise the code is totally screwed
e=block(....)
blockArray{ii}=e
end
This solution is very simple but slower than the first. You also lose some functionality which is not available for cell arras
Let your class implement array functionality
classdef A
properties
arg1
out
end
methods
function obj = A(varargin)
if nargin==0
%null object constructor
elseif strcmpi(varargin{1},'createarray')
sz=varargin(2:end);
%preallocate
obj(sz{:})=A;
else
%standard constructor
obj.arg1=varargin{1};
obj.out=[1 2 3;];
end
end
end
end
Constructor with no input argument creates an "empty" or "null" object, this is used to preallocate so it should be empty.
Constructor with first parameter makearray creates an array
Otherwise your constructor should be called.
Usage:
%create an empty object
A
%create an array of size 2,3,4
A('createarray',2,3,4)
%use the standard constructor
A(2)
Biggest downside is you have to modify your classes. Never tested this solution, but it should be close to the first in performance.

Sort ArrayBuffer[A] in scala?

I have an array in Scala with the class ArrayBuffer[Actor], where Actor is a class that implements the Ordered[Actor] trait. How do I sort this array without coding it manually?
I know there is an object called Sorting, but it doesnt seem to work since ArrayBuffer doesn't implement/extend the right classes.
How do I sort ArrayBuffer[A] type arrays?
If you are using Scala 2.8, you could use the sortWith method of the ArrayBuffer[T] class, which is inherited from the SeqLike trait.
The following code snippet sorts an ArrayBuffer[T] object in ascending order:
def ascendingSort[T <% Ordered[T]](xs: ArrayBuffer[T]) = xs.sortWith(_ < _)
Note that this does not mutate the actual ArrayBuffer, but creates a new one with the elements in the right order.
If you are using Scala 2.7, you could use the stableSort method of the Sorting object. This takes the elements of the ArrayBuffer and produces an array of elements sorted in the right order (given by a closure as an argument, ascending as a default).
For example:
val a = new scala.collection.mutable.ArrayBuffer[Int]()
a += 5
a += 2
a += 3
scala.util.Sorting.stableSort(a)
The important question is what do you want to do with the ArrayBuffer. Usually, a Buffer is used internally in different algorithms in order to increase the performance of intermediate results. If you are using it for that, have a look at the ways of sorting the collection you want to return at the end of your algorithm. The Sorting object already provides a way of transforming an ArrayBuffer into a sorted Array.
From the scaladoc of the Buffer class:
Buffers are used to create sequences of elements incrementally
As you are using it with Actors, it might be used for some kind of actor queue - in which case, you might want to have a look at the Queue collection.
Hope it helps,
-- Flaviu Cipcigan
Btw, the Actor class here is my own class used for "Actors" in a world created using my new game engine for scala ("Awesome Game Engine for Scala ~ AGES"), so it has nothing to do with the concurrency actor class. Also, implementations of lists in scala are a jungle, everything is either deprecated or implemented in a lot of different ways...ArrayBuffer works for my need (my need being a variable size array for containing actors).
Hope this clarifies :)

Resources