I'm relatively new to ruby and i came from php. One thing that it seems i would not understand is the difference between hashes and arrays. How do you implement associative arrays in ruby? Eg.
$albums = array();
$songs = array();
$songs[] = array('title' => 'Title 1', 'artist' => 'Artist 1', 'album' => 'Album 1');
$songs[] = array('title' => 'Title 2', 'artist' => 'Artist 2', 'album' => 'Album 2');
$songs[] = array('title' => 'Title 3', 'artist' => 'Artist 1', 'album' => 'Album 1');
$songs[] = array('title' => 'Title 4', 'artist' => 'Artist 1', 'album' => 'Album 1');
$songs[] = array('title' => 'Title 5', 'artist' => 'Artist 3', 'album' => 'Album 1');
foreach($songs as $song)
{
if( !isset($albums[$song['album']]) ) $albums[$song['album']] = array();
$albums[$song['album']]['title'] = $song['album'];
$albums[$song['album']]['songs'] = $song;
}
print_r($albums);
['Album 1']
=> 'title' => 'Album 1'
=> 'songs'
=> 'title' => 'Title 1', 'artist' => 'A开发者_C百科rtist 1', 'album' => 'Album 1'
=> 'title' => 'Title 3', 'artist' => 'Artist 1', 'album' => 'Album 1'
=> 'title' => 'Title 4', 'artist' => 'Artist 1', 'album' => 'Album 1'
=> 'title' => 'Title 5', 'artist' => 'Artist 3', 'album' => 'Album 1'
['Album 2']
=> 'title' => 'Album 2'
=> 'songs'
=> 'title' => 'Title 1', 'artist' => 'Artist 1', 'album' => 'Album 1'
Or even, instead of title and songs i can declare an array album info with title, artist and how many songs.
How can i do something similar with ruby? what i would use to accomplish that?
A more-or-less direct rewrite from your PHP:
albums = {}
songs = [
{ :title => 'Title 1', :artist => 'Artist 1', :album => 'Album 1' },
{ :title => 'Title 2', :artist => 'Artist 2', :album => 'Album 2' },
{ :title => 'Title 3', :artist => 'Artist 1', :album => 'Album 1' },
{ :title => 'Title 4', :artist => 'Artist 2', :album => 'Album 1' },
{ :title => 'Title 5', :artist => 'Artist 3', :album => 'Album 1' }
]
songs.each do |song|
album = albums[song[:album]] ||= {}
album[:title] = song[:title]
(album[:songs] ||= []).push(song)
end
puts albums.inspect
Easier would be the one-liner:
albums = songs.group_by { |song| song[:album] }
Arrays have only integer keys, and allocate all of them up to the highest one (so if you assign foo[100] = 1
, there will be locations for keys 0-99 also occupying memory (with nil
value); you note array values with square brackets: [1, 2, 3]
is a 3-element array, []
is empty.
Hashes are enclosed in curly braces {}
, and can have pretty much anything as keys. However, blocks can also be written with braces, so take care not to confuse the two.
You should be able to use a Ruby Hash exactly like a PHP associative array.
As you mentioned in the title of your question, associative arrays are usually referred to as hashes in Ruby. The syntax is slightly different from arrays.
# Normal array
normArray = ["SomeSong", "SomeGuy"]
anotherNormArray = Array.new
# Literal hash
literalHash = { "Title" => "SomeSong", "Artist" => "SomeGuy" }
# Declared beforehand
declaredHash = Hash.new
declaredHash["Songs"] = literalHash
You can do it in one line
songs = [
{'title' => 'Title 1', 'artist' => 'Artist 1', 'album' => 'Album 1'},
{'title' => 'Title 2', 'artist' => 'Artist 2', 'album' => 'Album 2'},
{'title' => 'Title 3', 'artist' => 'Artist 1', 'album' => 'Album 1'},
{'title' => 'Title 4', 'artist' => 'Artist 1', 'album' => 'Album 1'},
{'title' => 'Title 5', 'artist' => 'Artist 3', 'album' => 'Album 1'}
]
songs.group_by{|h| h[:album]}.inject({}){|h,(album,s)| h[album] = {:title => album, :songs => s }; h }
#=> {"Album 1"=>{:songs=>[{:artist=>"Artist 1", :album=>"Album 1", :title=>"Title 1"}, {:artist=>"Artist 1", :album=>"Album 1", :title=>"Title 3"}, {:artist=>"Artist 2", :album=>"Album 1", :title=>"Title 4"}, {:artist=>"Artist 3", :album=>"Album 1", :title=>"Title 5"}], :title=>"Album 1"}, "Album 2"=>{:songs=>[{:artist=>"Artist 2", :album=>"Album 2", :title=>"Title 2"}], :title=>"Album 2"}}
Only I don't understand why do you use Album title twice: as a hash key and as a title param? You should use only once, I think :)
精彩评论