Related
I am writing code in Ruby.
Say I have an array like this:
myarray = [1,2,3,4,5]
I want to change the code of the Array class so that myarray[7] would return "out of bounds" instead of nil.
I don't want to make so that I check if something is out of bounds and then return "out of bounds", I want to implement this in Array directly.
Is this possible? Do I have to extend the Array class?
I'm Not sure how to start, very new to ruby. My initial thoughts were overriding a method in the Array class, but I'm not sure how to do that when I don't know what method is being used in myarray[i].
Suppose
arr = [1,2,3,4,5]
Let's start by examining the doc Array#[]. As seen, that method can have a single integer argument:
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> nil
arr[-7] #=> nil
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have two integer arguments:
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
or it may have a range of integers as an argument:
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
As I understand, you wish to alter Array#[] in such way that its behavior is unchanged except for the case when its argument is a single integer representing an offset into the array that is out-of-bounds.1. That could be done by writing the method in a module and then prepend that module to the class Array with the method Module#prepend.
module NewSlice
def [](*args)
arg1, arg2 = args
if arg2.nil? && arg1.is_a?(Integer) &&
(arg1 > self.size-1 || arg1 < -self.size)
"out of range"
else
super
end
end
end
Array.prepend(NewSlice)
arr[2] #=> 3
arr[-2] #=> 4
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr['x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1,3] #=> [2, 3, 4]
arr[-3,2] #=> [3, 4]
arr[3,5] #=> [4, 5]
arr[7,4] #=> nil
arr[2,'x'] #=> TypeError (no implicit conversion of String into Integer)
arr[1..3] #=> [2, 3, 4]
arr[1...3] #=> [2, 3]
arr[-5..-2] #=> [1, 2, 3, 4]
arr[3..9] #=> [4, 5]
arr[7..10] #=> nil
arr[1..'x'] #=> ArgumentError (bad value for range)
We see that
Array.ancestors
#=> [NewSlice, Array, Enumerable, Object, Kernel, BasicObject]
showing that super in NewSlice#[] calls the original method Array#[] after NewSlice has been prepended to Array. Since super has no arguments all the arguments that were passed to the new Array#[] method ( defined in NewSlice) are passed to the original Array#[].
Aliases were commonly used in Ruby prior to the introduction of Module#prepend in Ruby v2.0. They are still used but their importance has diminished greatly since prepend has become available.
If nil is to be replaced by "out of bounds" in all cases where Array#[] returns nil, write
module NewSlice
def [](*args)
super || "out of bounds"
end
end
Array.prepend(NewSlice)
arr[5] #=> "out of range"
arr[-7] #=> "out of range"
arr[7,4] #=> "out of range"
arr[7..10] #=> "out of range"
1. Whether it is advisable to modify core methods such as Array#[] is a separate question, but it can result in pain and suffering.
TL;DR
This is an interesting question about how to monkeypatch core Ruby classes like Array. However, I'd be remiss if I didn't point out that it involves some hijinks that seem unnecessary, since you could get the same behavior with a simple logical OR operator like:
[1, 2, 3][5] || 'out of bounds'
#=> "out of bounds"
Still, if you want to change the behavior of a core class then it can certainly be done.
Re-Open the Core Class
In Ruby, almost everything that isn't a keyword is a method. Pragmatically, Array::[] is really just a method for indexing into an array object, with a little syntactic sugar from the interpreter to allow its arguments to be placed inside the brackets. Because it's just an instance method defined by the Array class, it can be modified in various ways such as re-opening the core class to modify the method, or by creating a singleton method on the instance. The first is conceptually simpler, but singleton methods are probably the safest solution for real-world programming.
You can re-open the Array class and redefine Array::[] as follows:
class Array
# save off a copy of the existing method; we still need it
alias_method :'old_[]', :'[]' unless defined? Array::old_[]
# pass all arguments to the old method, but return a string
# when the result is falsey
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
You can then demonstrate that it works like a regular Array, but with your expected behavior:
a = [10, 20, 30]
a[0] #=> 10
a[0,2] #=> [10, 20]
a[100] #=> "out of bounds"
Add a Singleton Method
While the code above works, it's just generally a bad idea to monkeypatch a core class like Array. If you don't want to encapsulate this behavior in a subclass (e.g. class MyArray < Array), then you should use refinements (using Module#refine) or singleton methods like the following to reduce the scope of your changes. For example:
a = [10, 20, 30]
class << a
alias_method :'old_[]', :'[]' unless self.respond_to? 'old_[]'
def [] *args
send("old_[]", *args) || 'out of bounds'
end
end
By limiting the scope of our change to a single instance, we're much less likely to cause serious or unrecoverable problems with core classes. A lot of things can go wrong in a Ruby program if a core class like Array starts returning truthy values (e.g. a String value such as out of bounds) rather than a falsey value like nil, so caveat emptor!
If you really want to break existing code (standard classes and ruin even methods of the current Array class itself, which rely on the current behaviour), you can of course monkeypatch it - open it and redefine the method in any way you like, as has been outlined in various answers to this question.
A more sane approach would be to subclass Array, i.e.
class BoundCheckingArray < Array
# redefined the methods according to your taste.
end
Of course this would violate the Liskov Substitution Principle.
Another approach will be to define a complete separate class and use Delegator to avoid rewriting everything from scratch, by delegating methods you did not rewrite explicitly, to the underlying array.
In both cases you need to be aware, that those methods in your BoundCheckingArray, which you did not explicitly rewrite and hence are taken from BoundCheckingArray, will stop working, if they assume that they can safely access the array outside of the bounds.
Another possibility would be to not modify existing Array methods, but simply add bound checking setters and getters, i.e. with monkeypatching:
class Array
def at_checked(i)
fail "out_of_bounds" if i >= size || i < -size
at(i)
end
def set_checked(i, new_value)
# analoguous
end
end
Of course this approach would also work with subclassing (now adhering to Liskov's principle, because you just added methods) and delegating. Note that I coped explicitly with negative index values, assuming that you would like to use this feature in your bound checking array too.
You may know classes in Ruby are defined like:
class Foo
def foo
'foo'
end
end
Foo.new.foo # calls instance method `foo` on the instance of `Foo`
# => 'foo'
Classes and modules in Ruby can be "reopened" for re-definition (although it's a bit frowned upon -- makes it difficult to track code b/c code can be in either/any place):
class Foo
def bar
'bar'
end
def foo
'overwrite foo'
end
end
f = Foo.new
f.bar
# => 'bar'
f.foo
# => 'overwrite foo'
This means you can also do:
class Array
# re-define anything you want
end
# alternatively:
Array.class_eval do
# the same as the above, in most ways
end
Even though it's even less recommended to modify existing methods of core Ruby classes. Not only does it break assumptions other Ruby developers may have of the code (i.e. misleading code), its global effect will likely break behaviors in other libraries, etc.
Can you give explanation of logic or algorithm of ruby behaviour for this construction:
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
How to formalize logic when iterate through Enumerable give 2 arrays output.
When we just call single partition its clear - just method behavior, but when it trails by with_index this construction become "Magical" for me.
Thank you
UPD: The condition is not in block of partition, it is in separate 'Enumerable' Object method block. This method is with_index. This second level of interaction is interesting for me. Why do conditions of with_index have influence on partition result? This is a behavior that is not clear from partition documentation.
You've probably read in the Ruby docs for partition:
If no block is given, an enumerator is returned instead.
> arr = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
> arr.partition
=> #<Enumerator: ...>
You'll see the same thing in the description for a lot of the methods in Enumerable but there isn't much detail about the enumerator that's returned.
The key to the enumerator chaining is in the the behaviour of the each method in the Enumerator that's returned. For example, the Enumerator returned by partition has an each method that behaves like partition. This is how you're able to pass a single block and get the combined behaviour of partition and with_index. If you do this in a couple of steps it might help:
> enumerator = arr.partition
=> #<Enumerator: ...>
> enumerator.each { |n| n < 3 } # just to demonstrate `each` performing a partition
=> [[1, 2], [3, 4, 5]]
> enumerator.with_index { |_, index| index > 2 }
=> [[4, 5], [1, 2, 3]]
Another way to think about it is that partition with no block given is like passing :partition to enum_for e.g.
> another_enum = arr.enum_for(:partition)
=> #<Enumerator: ...>
> another_enum.with_index { |_, index| index > 2 } # same result as above
=> [[4, 5], [1, 2, 3]]
When the index is > 2 ruby create a new array with the rest of values
partition
Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.
If no block is given, an enumerator is returned instead.
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
=> [[4, 5], [1, 2, 3]]
First array will contains [4,5] because it satisfys the condition index > 2.
Second array will contains all other elements: [1,2,3]
You are conflating the Enumerable module and the Enumerator class. All methods in the module Enumerable are instance methods that require their receiver to be an enumerator (an instance of the class Enumerator).
You use "include Enumerable" in your custom class and implement an each method which returns an enumerator:
def each
return enum_for(:each) unless block_given?
#apples.each { |apple| yield apple }
end
When a method contained in Enumerable is executed on an instance of a class that includes Enumerable, Ruby inserts the method each IMPLICITLY between the instance and the Enumerable method.
with_index is NOT a method of Enumerable module. It is an instance method of the Enumerator class. Now remember I stated that when you include Enumerable module in your custom class and implement an each method, that each method can be used to return an enumerator instance. So, classes that have a method each that returns an enumerator can make use of the method Enumerator#with_index by (explicitly) inserting each between an instance of the class and with_index. Or it can invoke with_index on the enumerable module method since that returns an enumerator instance:
arr = [1,2,3,4,5]
arr.partition.with_index{|_,index| index>2}
In the above example, partition is an instance method of Enumerable module and with_index is an instance method of Enumerator class. partition returns an enumerator instance which can take with_index.
Now for understanding what this statement does, you can simply look at the Enumerable docs which explains what partition does:
Returns two arrays, the first containing the elements of enum for which the block evaluates to true, the second containing the rest.
So in your case, it is determining whether the index is greater than 2. If it is, it gets put in one array, otherwise the other.
I am still learning Perl 6. Please pardon my ignorance. I am reading the Operators page and I found some unfamiliar constructs at the start of a table:
A Level Examples
N Terms 42 3.14 "eek" qq["foo"] $x :!verbose #$array
I re-read class Array and class Scalar but I am unable to find #$xyz construct in those sections. What do :! and #$ mean? Is there a convenient place that gathers and explains all these symbolic constructs?
Thank you very much !!
#$foo is short for #($foo), where $foo is an item variable and the #(...) syntax simply calls the .list method on its argument. Both the method and the syntactic form are sometimes called the "list/array contextualizer".
One use for it, is when you want to iterate over an Array stored in an item container. An item container is considered a single item by built-ins such as for loops, whereas calling .list on it returns the plain Array without the surrounding item container (i.e. "forces the value to be interpreted in list context"):
my $foo = [1, 2, 3];
say $foo.perl; # $[1, 2, 3]
say $foo.list.perl; # [1, 2, 3]
say #$foo.perl; # [1, 2, 3]
for $foo { ... } # One iteration
for $foo.list { ... } # Three iterations
for #$foo { ... } # Three iterations (identical to the previous line)
:!foo is short for :foo(False), i.e. a named argument that has the value False:
sub do-something (:$verbose = True) { say $verbose; }
do-something; # True
do-something :verbose; # True
do-something :!verbose; # False
When written in term position but not as an argument of an argument list, it constructs a Pair object:
say (:!verbose); # verbose => False
Using a :verbose parameter would be a good way to set a Bool argument to True with a colon pair. It is equivalent to :verbose(True). :!verbose is just the negation of that, setting it to False, equivalent to :verbose(False).
#$ is a way of using the # prefix to remove the container from a scalar variable with sigil $.
Consider:
my $x = (1, 2, 3);
.say for $x;
Output:
(1 2 3)
vs.
my $x = (1, 2, 3);
.say for #$x;
Output:
1
2
3
Most operators can be searched for directly. These two cases in particular are not individual operators, but cases of using symbols in combination. Those are a little more difficult gather conveniently, but the docs are improving every day.
I have multiple nodes with same label. The node properties have two arrays. I want join both array values to an object or a map.
Example:
Array one: [1,2,3,4,5]
Array two: [5,4,3,2,1]
I want to return result as {output:[{1,5},{2,4},{3,3},{4,2},{5,1}]} so a total of 5 objects in that output result.
Is this possible in Cypher?
WITH [1,2,3,4,5] AS array_one, [5,4,3,2,1] AS array_two
UNWIND RANGE(0, SIZE(array_one) - 1) AS i
WITH [array_one[i], array_two[i]] AS output
WITH COLLECT(output) AS output_list
RETURN {outputs: output_list}
That will give you a map, whose sole value is a list of lists. If you want to dynamically build a list of maps instead (your question's syntax is ambiguous), you will have to look into apoc, Cypher doesn't natively support dynamic key assignment.
APOC procedures may be the way to go on this one. In the Collection Functions section, the procedure you want is apoc.coll.zip([list1],[list2]). It is similar to what you want, but not exact. Rather than returning a list of objects, it will return a list of list pairs:
with [1,2,3,4,5] as list1, [5,4,3,2,1] as list2
call apoc.coll.zip(list1,list2) yield value
return {outputs:value}
// returns {outputs:[[1, 5], [2, 4], [3, 3], [4, 2], [5, 1]]}
Regarding your desired output, objects in Cypher are like JSON objects and consist of key/value pairs, so it is impossible to return it in the format you're describing. You can test this for yourself.
// this works just fine
return {output: [[1,2]]}
// this causes a syntax error
return {output: [{1,2}]}
Array of maps
You can generate a map containing an array of maps without using APOC:
WITH [1,2,3,4,5] AS a1, [5,4,3,2,1] AS a2
RETURN {output: REDUCE(s = [], i IN RANGE(0, SIZE(a1)-1) | s + {one: a1[i], two: a2[i]})} AS res;
The output is:
{output:[{"one":1,"two":5},{"one":2,"two":4},{"one":3,"two":3},{"one":4,"two":2},{"one":5,"two":1}]}
Array of arrays
To generate a map containing an array of arrays:
WITH [1,2,3,4,5] AS a1, [5,4,3,2,1] AS a2
RETURN {output: REDUCE(s = [], i IN RANGE(0, SIZE(a1)-1) | s + [[a1[i], a2[i]]])} AS res;
The output is:
{output:[[1,5],[2,4],[3,3],[4,2],[5,1]]}
I'm working my way through Learning Ruby the Hard Way online; I've just finished the 26th exercise which was a "test" whereby you fixed someone's broken code.
My problem came with using an argument with the pop method. I'm familiar with the basics but the correct answer meant changing the argument from "-1" to "1", and I'm not sure what it means, exactly.
The line in question is:
def puts_last_word(words)
word = words.pop(1)
puts word
end
I assume it pops the second element from the array but I would like confirmation or help, whichever is appropriate.
The best confirmation can be had in the documentation of Array#pop: http://rubydoc.info/stdlib/core/1.9.3/Array:pop
According to that, the argument specifies how many elements, counting from the back of the array, to remove.
The only difference between pop() and pop(1) is that the former will return a single element (the deleted one), while the latter will return an array with a single element (again, the deleted one).
Edit: I suppose the reason the test used -1 is to teach you about the difference between array access with #[], where -1 would mean the last element, and methods like pop, that expect an amount, not a position, as their argument.
The argument specifies how many items to pop. If you specify an argument it returns an array whereas not specifying an argument returns just the element:
ruby-1.8.7-p352 :006 > a = [1,2,3]
=> [1, 2, 3]
ruby-1.8.7-p352 :007 > a.pop(1)
=> [3]
ruby-1.8.7-p352 :008 > a = [4,5,6]
=> [4, 5, 6]
ruby-1.8.7-p352 :009 > a.pop(2)
=> [5, 6]
ruby-1.8.7-p352 :010 > a.pop
=> 4