Ruby koan - about arrays - test_accessing_array_elements array[5,0] [duplicate] - ruby

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Why does array.slice behave differently for (length, n)
In Ruby koan "about_arrays.rb", test_accessing_array_elements there's two similar start/length slice statements accessing parts of an array. Ref extract below. Both should be "out of range" yet one returns an empty array and the other returns nil. This matches possible results as per docs ruby doc. Why is it so?
irb(main):221:0> array = [:peanut, :butter, :and, :jelly]
=> [:peanut, :butter, :and, :jelly]
irb(main):222:0> array[4,0]
=> []
irb(main):223:0> array[5,0]
=> nil
irb(main):224:0>
irb(main):224:0> array[4]
=> nil
irb(main):225:0> array[5]
=> nil
irb(main):226:0>

I think of it as some array methods referring to the gaps between elements, rather than the elements themselves, i.e. 0 is the space before the first element, 1 the space between the first and second element. Considered this way, the operation makes slightly more sense, as 4 is the gap after the fourth element, which is still within the array, so zero elements from this position is an empty array.
You can think of the insert method in the same way (although the documentation explicitly says otherwise).
However, this is probably a mental trick rather than an explanation - still, perhaps it will help someone.

Related

Why are there slight different behaviors with array accesses? [duplicate]

This question already has answers here:
Array slicing in Ruby: explanation for illogical behaviour (taken from Rubykoans.com)
(10 answers)
Trying to understand Ruby arrays [duplicate]
(1 answer)
Closed 9 years ago.
My array is:
array = [:peanut, :butter, :and, :jelly]
array[4,0] gives []
But:
array[5,0] gives nil
I was suspecting array[4,0] should also give nil as the array has only a third index which is :jelly.
Can any Ruby punters out there clarify this behaviour?
It's all in the documentation:
Additionally, an empty array is returned when the starting index for an element range is at the end of the array.
Returns nil if the index (or starting index) are out of range.

Is the order of each_value for Ruby's hashes defined?

Is the order of the values returned by Ruby's Hash::each_value{ |val| block } somehow defined? I.e. for a given hash is the order of values in the iterations of the loop always* the same?
I wonder if it is so, as the key-value pairs of hashes are not sorted unlike the values of an array.
Given the following example:
myhash = { :a => 100, :b => 200, :z => 9, :e => 101 }
myhash.each_value { |val|
puts val
}
Does Ruby ensure it always* prints
100
200
9
101
Bonus question in case it is defined:
What are the prerequisites that the order is defined? Does it only apply for hard-coded hashes as the example?
[*]: "always" should be read as 'on each execution and on any system with a working Ruby 1.9+'.
In Ruby 1.8, Hashes are not ordered and the values will be returned in an arbitrary order that you cannot depend upon. In Ruby 1.9, Hashes are ordered based on the time the keys were inserted (first insertion positioned first, etc...).
You specified in a footnote that "'always' should be read as 'on each execution and on any system with a working Ruby 1.9+'.". By that definition of "always", the answer is "yes" ;)
From the Ruby 1.8.7 Hash docs:
The order in which you traverse a hash by either key or value may seem
arbitrary, and will generally not be in the insertion order.
From the Ruby 1.9.3 Hash docs:
Hashes enumerate their values in the order that the corresponding keys were inserted.
In Ruby 1.9 the order is insertion order.
Some info from ~three years ago when this was news:
YCombinator discussed a possible usecase
And some internals info

Learning Ruby: Making infinite dimensional array via block abuse

Somebody tell me what's going on here:
a = [0,1,2]
a.each {|x| a[x] = a}
The result is [[...], [...], [...]]. And if I evaluate a[0] I get [[...], [...], [...]]. And if I evaluate a[0][0] I get [[...], [...], [...]] ad infinitum.
Have I created an array of infinite dimensionality? How/Why should this possibly work?
Basically you've modified every element in a to reference the list itself. The list is recursively referencing itself:
a[0] # => a
a[0][0] # => a[0], which is a
a[0][0][0] # => a[0][0], which is a[0], which is a
...
(# => is a Rubyism for "this line evaluates to")
Depending on how you look at it it is not infinite. It's more or less just like a piece of paper with the words "please turn over" written on both sides.
The reason that Ruby prints [...] is that it is clever enough to discover that the list is recursive, and avoids going into an infinite loop.
By the way, your usage of each is a bit non-idiomatic. each returns the list, and you usually don't assign this return value to a variable (since you already have a variable referencing it, a in this case). In other words, your code assigns [0,1,2] to a, then loops over a (setting each element to a), then assigns a to a.
I think it's a self-referential data structure. The a[x]=a puts a's pointer in a[x].

Ruby: Range is empty, but slicing with it produces elements

I'm learning Ruby and have just gotten into some stuff about arrays and ranges. I've run into something about slices that, while it makes sense at first glance, confuses me a bit when I look deeper into it.
IRB says that (2..-1).to_a is an empty array, meaning no values in the range, right?
But if I use that same range in [:a, :b, :c, :d, :e][2..-1], I get back [:c, :d, :e] rather than an empty array.
Now, I'm aware that -1 represents the last element of the array, so it kind of makes sense that what got picked, did. But if the range itself would be empty, how is it selecting anything?
This is a fascinating question. The answer is that it's not the individual elements of the range that are inspected when slicing the array, but the first and last elements. Specifically:
>> (2..-1).to_a
=> []
>> (2..-1).first
=> 2
>> (2..-1).last
=> -1
Thus the example works, since it slices the array from the [2] element to the [-1] element.
If you want a consistent way to think about this, consider that (2..-1).to_a outputs the integers found between 2 and -1 (of which there are none), but that [2..-1] means from the 2 index to the -1 index.
(Source: array.c and range.c in the Ruby source.)
And, the complicated bonus part: to get the meaning you were thinking about, you could use
>> [:a, :b, :c, :d, :e].values_at *(2..-1).to_a
=> []
In the slicing operation it's not seeing the range as a Range per se, it's just looking at the values of the endpoints, in this case 2 and -1. Since -1 has a special meaning (i.e last item in the list) it just returns everything from item at index 2 to the end of the list. Don't think of it as a Range here, just think of it as a convenient way of passing in two numbers (expressing two end points).
The Array#[] method does not use the range as a range (that is, it does not call include? on it or anything like that); it just takes the two numbers out of it and checks whether it's exclusive.
You can imagine it to look somewhat like this (though the real [] is implemented in C, not in Ruby, and of course also handles arguments other than ranges):
def [](range)
start = range.begin
length = range.end - start
length -= 1 if range.exclude_end?
slice(start, length)
end

Ruby: How to loop through an object that may or may not be an array?

I have an each method that is run on some user-submitted data.
Sometimes it will be an array, other times it won't be.
Example submission:
<numbers>
<number>12345</number>
</numbers>
Another example:
<numbers>
<number>12345</number>
<number>09876</number>
</numbers>
I have been trying to do an each do on that, but when there is only one number I get a TypeError (Symbol as array index) error.
I recently asked a question that was tangentally similar. You can easily force any Ruby object into an array using Array.
p Array([1,2,3]) #-> [1,2,3]
p Array(123) #-> [123]
Of course, arrays respond to each. So if you force everying into an array, your problem should be solved.
A simple workaround is to just check if your object responds to :each; and if not, wrap it in an array.
irb(main):002:0> def foo x
irb(main):003:1> if x.respond_to? :each then x else [x] end
irb(main):005:1> end
=> nil
irb(main):007:0> (foo [1,2,3]).each { |x| puts x }
1
2
3
=> [1, 2, 3]
irb(main):008:0> (foo 5).each { |x| puts x }
5
=> [5]
It looks like the problem you want to solve is not the problem you are having.
TypeError (Symbol as array index)
That error tells me that you have an array, but are treating it like a hash and passing in a symbol key when it expects an integer index.
Also, most XML parsers provide child nodes as array, even if there is only one. So this shouldn't be necesary.
In the case of arguments to a method, you can test the object type. This allows you to pass in a single object or an array, and converts to an array only if its not one so you can treat it identically form that point on.
def foo(obj)
obj = [obj] unless obj.is_a?(Array)
do_something_with(obj)
end
Or something a bit cleaner but more cryptic
def foo(obj)
obj = [*obj]
do_something_with(obj)
end
This takes advantage of the splat operator to splat out an array if it is one. So it splats it out (or doesn't change it) and you can then wrap it an array and your good to go.
I was in the same position recently except the object I was working with was either a hash or an array of hashes. If you are using Rails, you can use Array.wrap because Array(hash) converts hashes to an array.
Array({foo: "bar"}) #=> [[:foo, "bar"]]
Array.wrap({foo: "bar"}) #=> [{:foo=>"bar"}]
Array.wrap(123) #=> [123]
Array.wrap([123]) #=> [123]
I sometimes use this cheap little trick:
[might_be_an_array].flatten.each { |x| .... }
Use the splat operator:
[*1] # => [1]
[*[1,2]] # => [1,2]
Like Mark said, you're looking for "respond_to?" Another option would be to use the conditional operator like this:
foo.respond_to? :each ? foo.each{|x| dostuff(x)} : dostuff(foo);
What are you trying to do with each number?
You should try to avoid using respond_to? message as it is not a very object oriented aproach.
Check if is it possible to find in the xml generator code where it is assigning an integer value when there is just one <"number"> tag and modify it to return an array.
Maybe it is a complex task, but I would try to do this in order to get a better OO design.
I don't know much anything about ruby, but I'd assume you could cast (explicitly) the input to an array - especially given that if the input is simply one element longer it's automatically converted to an array.
Have you tried casting it?
If your input is x, use x.to_a to convert your input into an array.
[1,2,3].to_a
=> [1, 2, 3]
1.to_a
=> [1]
"sample string".to_a
=> ["sample string"]
Edit: Newer versions of Ruby seem to not define a default .to_a for some standard objects anymore. You can always use the "explicit cast" syntax Array(x) to achieve the same effect.

Resources