TODO - this ought to be absorbed into https://github.com/spiralofhope/ruby-random/tree/master
This code was tested and works on Ruby 1.9.2
https://ruby-doc.org/core-1.9.2/Array.html
As with everything, there are multiple ways to do something. When faced with multiple choices, I just picked one method I felt was straightforward and went with it and ignored the rest.
Arrays ∞
To avoid any messy gotchas, initialize your arrays with Array.new
. For example:
a = Array.new
A "1d" (one-dimensional) array with two elements looks like this:
a = [ "0x", "1x" ]
Instead of having all elements in one row, it's possible to arrange it as a column:
a = [ "0x", "1x", ]
Notice how it looks a lot nicer.
I'm now able to comment in a straightforward way:
a = [ "0x", # The left side "1x", # The right side. ]
I ended the final entry with a comma. This is optional, but helpful for those of us who like to cut-and-paste to move entries up and down in that array.
Examples ∞
Creating an array / adding elements ∞
a = Array.new a << "one" a << "two" puts a.inspect # => # ["one", "two"]
Retrieving elements ∞
a = [ "one", "two", "three", ] puts a[0].inspect # => # "one" puts a[-1].inspect # => # "three" puts a[0..1].inspect # => # ["one", "two"] puts a[1..-1].inspect # => # ["two", "three"]
2d Arrays ∞
If you kneel and look at the very edge of your desk, you can only see the front corners. It looks like a line.
If you stand and look at the top of your desk, you can see the full desktop with its four corners.
Let's make a desktop-like array with four elements arranged like a 2x2 square.
We can put four elements into an array like this:
a = [ "one", "two", "three", "four", ]
That isn't four points at the corners of a square, that's four points along a single line, because it is still a regular 1d array. A 2d array looks like:
a = [ # Imagine that this is the top-left corner of the 2d array's "box". [ # This begins the first row of the box: "0x,0y", # row 1, left side. "0x,1y", # row 1, right side. ], [ # A new, second, row: "1x,0y", # row 2, left side. "1x,1x", # row 2, right side. ], ] # Imagine that this is the bottom-right corner of the 2d array's "box".
You can imagine a 2x2 square with that. To make it into a "taller" 2x3 rectangle, you can add more rows on to the bottom.
a = [ [ "0x,0y", # row 1, left side. "0x,1y", # row 1, right side. ], [ # A new row: "1x,0y", # row 2, left side. "1x,1x", # row 2, right side. ], [ # A new row. "2x,0y", # row 3, left side. "2x,1x", # row 3, right side. ], ]
To add more "width" to our box, you would add more items like this.
a = [ [ # This begins the first row of the box: "0x,0y", # row 1, left side. "0x,1y", # row 1, right side. "0x,2y", # row 1, right side. "Widening" it. ], [ # A new row: "1x,0y", # row 2, left side. "1x,1x", # row 2, right side. "1x,2x", # row 2, right side. "Widening" it. ], ]
Examples ∞
Creating an array / adding elements ∞
row1 = Array.new row2 = Array.new row1 << "one" row1 << "two" puts row1.inspect # => # ["one, "two"] row2 << "three" row2 << "four" # => # ["three", "four"] array2d = [ row1, row2 ] # We can't call it "2darray" because you cannot start a variable with a number. puts array2d.inspect # => # [["one", "two"], ["three", "four"]]
Retrieving elements ∞
a = [ [ "one", "two", ], [ "three", "four", ] ] puts a[0].inspect # => # ["one", "two"] puts a[0][0].inspect # => # "one"
TODO - Retrieving a "box" of elements ∞
a = [ [ "one", "two", "three", ], [ "four", "five", "six", ] [ "seven", "eight", "nine", ] ] puts a[0..1].inspect # => # [["one", "two", "three"], ["four", "five", "six"]] a = [ [ # This is 0 "one", "two", "three", ], [ # This is 1 "four", "five", "six", ] [ "seven", "eight", "nine", ] ]
Missing elements ∞
It's perfectly fine to have missing elements in our array-box. Let's imagine we have a 3x3 array:
a = [ [ "0x,0y", # row 1, left side. "0x,1y", # row 1, middle. "0x,2y", # row 1, right side. ], [ "1x,0y", # row 2, left side. "1x,1x", # row 2, middle. "1x,2x", # row 2, right side. ], [ "2x,0y", # row 3, left side. "2x,1x", # row 3, middle. "2x,2x", # row 3, right side. ], ]
If we imagine it as a bunch of Xs, it looks like this:
XXX XXX XXX
But it's ok to have an array with any of those removed. I'll represent them with a middot ( · ).
XX· X·X XXX
a = [ [ "0x,0y", # row 1, left side. "0x,1y", # row 1, middle. # row 1, right side. Removed. ], [ "1x,0y", # row 2, left side. # row 2, middle. Removed. "1x,2x", # row 2, right side. ], [ "2x,0y", # row 3, left side. "2x,1x", # row 3, middle. "2x,2x", # row 3, right side. ], ]
If we simply cut out those entries, then the array will collapse. Elements will "shift over".
XXX XX· XX XXX => X·X => XX XXX XXX XXX
As the array collapses in on itself, one of its elements will change so that it is accessed in a different way from before. It's easier to explain with numbers.
You might be tempted to think of it like this:
012 01· 012 => 0·2 012 012
But it's actually doing this:
012 01· 01 012 => 0·? => 01 012 012 012
This is because the "columns and rows" concept does not really apply to arrays! It's an easy convention to think of 1d arrays as being parts of a line, and to think of 2d arrays as being parts of a square or rectangle, but these are not how things actually work.
To explain better, let's show the above code again and comment it with actual Ruby code.
a = [ [ "1", # a[0][0] "2", # a[0][1] "3", # a[0][2] ], [ "4", # a[1][0] "5", # a[1][1] "6", # a[1][2] ], [ "7", # a[2][0] "8", # a[2][1] "9", # a[2][2] ], ] puts a.inspect # => # [["1", "2", "3"], ["4", "5", "6"], ["7", "8", "9"]] a[0][2] = nil a[1][1] = nil puts a.inspect # => # [["1", "2", nil], ["4", nil, "6"], ["7", "8", "9"]] # Setting an element to "nil" is not removing them, it's just # emptying that element. # Delete the element at a[1][1] a[1].delete_at(1) puts a.inspect # => # [["1", "2", "3"], ["4", "6"], ["7", "8", "9"]] # Our existing numbering concept doesn't really work anymore. # Any time we fetch an element that has no content we will get nil. puts a[1][2] # => # nil puts a[1][1] # => # "6"
An element in an array can have some value. So a[1][1]
can be the number 6
. But its value has nothing to do with its actual "position" in the array.
So removing an element shifts everything over.
a[1].delete_at(1)
deleteda[1][1]
.a[1][2]
used to be6
but it becamenil
.-
a[1][1]
used to be5
but it became6
.
Fetching nonexistent elements ∞
Any time we fetch an element that has no content we will get nil
. This is true for a 1d array:
a = [ 1, 2, ] puts a[99] # => # nil
This is not entirely true for a 2d array:
a = [ [ 1, 2, ], [ 3, 4, ], ] puts a[99] # => # nil puts a[99][99] # => # NoMethodError: undefined method `[]' for nil:NilClass
The a[99]
works the same as a 1d array would. But doing the equivalent of a[nil][99]
won't work, because nil
isn't actually an array!
Think of a 1d array as having infinite nil
s:
[1,2,nil,nil,nil,...]
But a 2d array has no such concept:
[ [1,2,nil,nil,nil,...] [1,2,nil,nil,nil,...] ] [ [1,2,nil,nil,nil,...] [1,2,nil,nil,nil,...] ··· ]
There is no concept of "infinite nil
-arrays" underneath there.
Last updated 2019-12-06 at 12:27:05