Array capacity limit in Ruby - ruby

I dont know how to set array capacity so my array can store only 3 elements. E.g. if I try to push 4th element, it returns error.
Any ideas?

The default Array class doesn't have that functionality. So, your options are:
Create a separate class that stores the three elements and implement your own methods like push and [].
Subclass Array and override the methods to only allow for three elements, for example:
class ThreeElements < Array
def push(*stuff)
raise 'Already has three elements!' unless length < 3
super
end
end
In my opinion, #1 is the better option, because the default Array interface has too many methods to bother with overriding.

You can create a wrapper class for your array! You can also override the "[]" operator in and check if your index is valid:
def [](i)
# getter
end
def []=(i, v)
# setter
end

Related

Using Enumerable to make standard iterators available to modify iterators

I am Attempting to Use the Enumerable mixin to make all the standard iterators available in my class named NumberArray . From that I'm trying to use the inject iterator to get the average of odd numbers in the array .
My code looks like this
class NumberArray
include Enumerable
def initialize
#numbers = Array.new
end
then #numbers array is then filled with 1000 numbers
and finally I'm trying to create my own inject iterator to get the average of the odd values.
def inject
puts self.inject{|sum,x| sum = sum + x if sum mod 2 == 1}
asum
end
I am very new to Ruby.
Classes that use the Enumerable mixin must have an each method, which yields for each successive element.
Since your class NumberArray is backed by a normal array, you can use the array's each method:
class NumberArray
# ...
def each
#numbers.each
end
end
As for your inject method, when you call self.inject, it just calls the method you're currently in again. This is called recursion, and will cause a SystemStackError in this case. I also don't recommend redefining the inject method in NumberArray, because it will override the Enumerable implementation of inject.
I'd use a more descriptive method name like odd_avg:
def odd_avg
odds = #numbers.select(&:odd?)
odds.inject(:+).to_f / odds.size
end
The first line of this method gets all the odd elements from #numbers and puts it into odds. The next line first gets the sum of odds, then converts the sum to a float, then divides by the number of odds.
You could also just subclass Array and override methods you want:
class NumberArray < Array
def inject
odds = select(&:odd?)
odds.inject(:+).to_f / odds.size
end
end
a = NumberArray.new([1,2,3,4,5])
a.inject # => 3.0
If it makes any sense to do it this way is another thing, but that's what you asked :)

Ruby enumerables don't keep the same class

I have a class that represents a collection. I included the Enumerable module into it and defined the method #each, so that I get all its methods.
But the problem is that Enumerable's methods don't keep the same class. So, for example, if my class is named Collection, and if I do Collection#select, I would like that the result's class is also Collection (instead of Array). Is there a way how to achieve this?
Since Enumerable#select is designed to return an array, you need to tell somewhere how to map that to a Collection instance. That means, you explicitly need to define Collection#select. Otherwise Ruby will not know the mapping rule from the original array result of Enumerable#select to a Collection instance.
Unfortunately, Ruby's Collection Operations are not type-preserving. Every collection operation always returns an Array.
For collections like Sets or Trees, this is merely annoying, because you need to always convert them back into the type you want to have. But for example for an infinite lazy stream of all prime numbers, this is catastrophic: your program will either hang or run out of memory trying to construct an infinitely large Array.
Most Collection APIs either eliminate duplicate code or are type-preserving, but not both. E.g. .NET's Collection API mostly eliminates duplicate code, but it always returns the same type: IEnumerable (equivalent to Ruby's Enumerator). Smalltalk's Collection API is type-preserving, but it achieves this by duplicating all Collection Operations in every Collection type.
The only Collection API which is type-preserving yet eliminates duplication is Scala's. It achieves this by introducing the new concept of Collection Builders, which know how to efficiently construct a Collection of a specific type. The Collection Operations are implemented in terms of Collection Builders, and only the Collection Builders need to be duplicated … but those are specific to every Collection anyway.
If you want type-preserving Collection Operations in Ruby, you need to either duplicate all Collection Operations in your own Collection (which would be limited to your own code), or redesign the entire Collection API to use Builders (which would require a major redesign of not only your own code but also the existing Collections including every third-party Collection ever written).
It's clear that the second approach is at least impractical if not impossible. The first approach also has its problems, though: Collection Operations are expected to return Arrays, violating that expectation may break other people's code!
You can take an approach similar to Ruby 2.0's lazy collection operations: you could add a new method preserve_type to your API which returns a proxy object with type-preserving Collection Operations. That way, the departure from the standard API is clearly marked in the code:
c.select … # always returns an Array
c.preserve_type.select … # returns whatever the type of c is
Something like:
class Hash
def preserve_type
TypePreservingHash.new(self)
end
end
class TypePreservingHash
def initialize(original)
#original = original
end
def map(*args, &block)
Hash[#original.map(*args, &block)
# You may want to do something more efficient
end
end
Another way could be to make Collection a proxy for the underlying array:
class Collection
def initialize( items= nil )
#items = items || []
end
def respond_to_missing?(method_name, include_private = false)
Enumerable.instance_methods.include? method_name
end
def method_missing name, *args, &block
if #items.respond_to? name
res = #items.send name, *args, &block
res.kind_of?( Array ) ? Collection.new(res) : res
else
super
end
end
end
in IRB:
col = Collection.new [1,2,3]
=> #<Collection:0x0000010102d5d0 #items=[1, 2, 3]>
col.respond_to? :map
=> true
col.map{|x| x * 2 }
=> #<Collection:0x000001009bff18 #items=[2, 4, 6]>
The following worked for me. I found only the filtering methods needed to be redefined. If we redefine all methods that return Array, this includes collect which should not be redefined.
include Enumerable
def select(&block)
self.class.new(super.select(&block))
end
def reject(&block)
self.class.new(super.reject(&block))
end

Possible to extend methods of Array in ruby?

I have an array of instances of e.g. class Result, I want to join names of results rather than results with a ',' like below:
#results=[result1, result2...]
results.join(", ") do |r|
r.name
end
results.join method should be an extensino methods of Array, I want it available to all arrays in my program.
Possible?
Yes, this is possible.
class Array
def join_names
collect(&:name).join(", ")
end
end
But this makes it more likely that you code will have namespace collisions with other libraries that add methods to the Array class.

Define a method that works on arrays of a specific type of object

In C# you can write an extension method like this:
public static Debt[] Foo(this Debt[] arr, int num)
{
// Do something
}
This would allow you to use Foo() on an array of debts: debts.Foo(3)
Can you do this in Ruby? I know you can write a method that will work on arrays:
class Array
def foo
# blah
end
end
but this works on all types of arrays, not just an array of Debts
Thanks in advance.
the extend method is adding the instance methods to a particular object. so in you case it would be:
class YourClass
def foo
# blah
end
end
debts.extend(YourClass)
debts.foo # now foo method is instance method of debts object
Actually it creates singleton class for debts object and then add to it the method. But you can't use this class, that's why it called "ghost" class
This would be a little tricky because Ruby arrays are not homogeneous. That is, you can store different types of objects inside of an array. That would lead me to a solution where I need to first verify that all objects in the array are of type Debt, and if they are then I can act on the array using foo.
You can continue to open up Array and add the foo method, but maybe you should create a FooArray instead and extend Array. This way you can redefine some methods such as << and push to ensure you only take Debts. Since you know that only Debts can be added to your array, you could call foo() without worry.
I believe you can do this by extending Ruby's Array class or better yet defining your own Array-like class and delegating the selected array methods to the native object.
Stack = Array.extract([
:last,
:push,
:pop,
:size,
:clear,
:inspect,
:to_s
])
Why this is better than the alternative methods is explained here.

Add a callback function to a Ruby array to do something when an element is added

I'd like to add something like a callback function to a Ruby array, so that when elements are added to that array, this function is called.
One thing I can think of is to override all methods (like <<, =, insert, ...) and call that callback from there.
Is there an easier solution?
The following code only invokes the size_changed hook when the array size has changed and it is passed the new size of the array:
a = []
class << a
Array.instance_methods(false).each do |meth|
old = instance_method(meth)
define_method(meth) do |*args, &block|
old_size = size
old.bind(self).call(*args, &block)
size_changed(size) if old_size != size
end if meth != :size
end
end
def a.size_changed(a)
puts "size change to: #{a}"
end
a.push(:a) #=> size change to 1
a.push(:b) #=> size change to 2
a.length
a.sort!
a.delete(:a) #=> size change to 1
You should probably create your own class that wraps array. You don't want to override a core class with a callback like you are describing, not only does that make the code brittle but it becomes less expressive for future developers who may not be expecting Array to make a callback.
Use the "Observer" pattern to be notified of changes in the size of the array you wish to observer: Ruby Observer This saves you from having to override all methods that add an element to the array

Resources