Both arrays and hashes are useful to group individual objects in your code. They both work with a simliar structure based on key-value pairing, and they are both extrememly flexible regarding their contents. The objects that are contained within can be of any type, even including arrays or hashes. That is where the simliarities end, as they both have very unique purposes.
The heart of the array is how it organizes information. Everything in an array is arranged sequentially, starting at 0 and counting upwards with integers. These integers represent the keys for the values that will be assigned to them. For example:
=> ["cat", "dog", 7.4, [1, 2, 3]]
I created this array with the "Array.new" (make sure you capitalize it!) command I assigned it to the variable called, "myArray". Contained within the brackets[] are the objects. Object 0 is the string "cat", object 1 is the string "dog", object 2 is the float number 7.4 and object 3 is an array of integers. What you put in each space is irrelevant. What is important is how you arrange them. Because when you want to retrieve the object from the array you call it like this:
cat
=> nil
Of course the last line shows that this returns "nil", because puts always returns nil. With this same example, if I was to call the array within the array it would look like this:
1
2
3
=> nil
You can also call multiple objects from the array by separating them with commas.
dog
7.4
=> nil
If you need to call every object in the array, to perform some action on each of them, you can incrementally call every element in the array by using the ".each" method. In addition, I'll use a "block" to display the data that it calls. (the block is the code that falls between the curly braces {}. A local variable is defined between the pipes || and is then processed like normal code. The variable is used by each object in the array, so it can be processed by the code, and then replaced when the next object is called.)
cat
dog
7.4
1
2
3
=> ["cat", "dog", 7.4, [1, 2, 3]]
Notice that this time it returned "["cat", "dog", 7.4, [1, 2, 3]]" instead of nil. This is because the .each method returns what is in the array.
Similar to arrays, hashes organize the objects that they contain with keys. The major difference being that there is no order to those keys, and the keys can be anything. Technically the keys could be numbers, but the hash wouldn't know to put them in order. As a matter of fact, if you wanted to be ridiculous about it, you could make a key an array or even another hash. This is not recommended.
Here's an example hash that I am creating with its implicit form. Hashes can also be created with the ".new" method, and arrays can be created implicitly.
=> {"pet1"=>"cat", "pet2"=>"dog", "float"=>7.4, "array"=>[1, 2, 3]}
Once again, I get the returned value from the last evaluated expressions, which in this case happens to be the hash I made. The difference between hashes and arrays isn't just the obvious syntax difference. If I were to try to call an object from the hash, like an array, it wouldn't work.
=> nil
This is because I didn't assign the key "2" to any of my values. In order to call an object from a hash you have to use the appropriate key. If I want to call object 2 (The third object in the hash, which happens to be 7.4) I have to use the key "float".
7.4
=> nil
Similar to arrays, you can call multiple elements by separating the keys with commas. You can also use the ".each" method to call the objects incrementally.
pet1 is the key for cat
pet2 is the key for dog
float is the key for 7.4
array is the key for [1, 2, 3]
=> {"pet1"=>"cat", "pet2"=>"dog", "float"=>7.4, "array"=>[1, 2, 3]}
The block used here had to be a bit more complex, because the ".each" method calls ever single item in the hash (key, then value). If I wanted to only call the values, there is a method called ".each_value" (there's also ".each_key") for that.