Casa do Código
cujo identificador é a String "452565", que corresponde ao isbn do ob-
jeto web_design_responsivo. Cada um destes containers possui um deter-
minado valor, no Hash acima o container 123454 possui como valor o objeto
teste_e_design, já o container, cujo identificado é 452565, possui como valor o
objeto web_design_responsivo.
Quando desejamos acessar o valor que está incluso dentro um Hash, basta in-
vocarmos o método [:chave] passando a chave identificadora do container:
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
hash = { "123454" => web_design_responsivo,
"452565" => web_design_responsivo }
p hash["123454"]
# => Autor: Tárcio Zemel, Isbn: 452565, Páginas: 189,
Categoria: web_design
Bem parecido com a maneira que acessamos valores dentro de um Array. A
diferença é que passamos um objeto que representa a chave identificadora, e não um
Integer que representa o índice, como acontece quando acessamos valores de um
Array.
Agora vou provar que o encapsulamento que fizemos ao definir a classe
Biblioteca nos ajudará a migrar sem sofrimentos de Array para Hash a es-
trutura que guardava os livros:
class Biblioteca
attr_reader :livros
def initialize
@livros = {} # Inicializa com um hash
end
def adiciona(livro)
@livros[livro.categoria] ||= []
@livros[livro.categoria] << livro
end
end
54
Casa do Código
Capítulo 4. Estruturas de dados
O código que instancia os livros e os guarda dentro da biblioteca, continua fun-
cionando.
biblioteca = Biblioteca.new
teste_e_design = Livro.new "Mauricio Aniche", 247, "123454",
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", 189, "452565",
:web_design
biblioteca.adiciona teste_e_design
biblioteca.adiciona web_design_responsivo
O problema agora é o método que utilizamos para retornar os livros que estão
dentro da nossa biblioteca, retornam um Hash e não mais um Array e a forma de
iterar sobre estas duas estruturas de dados são diferentes. A primeira opção é fazer
com que o método livros continue retornando um Array:
class Biblioteca
def adiciona(livro)
@livros[livro.categoria] ||= []
@livros[livro.categoria] << livro
end
def livros
@livros.values.flatten
end
end
Criando nossa própria implementação do método livros, conseguimos man-
ter o mesmo comportamento anterior, quando retornávamos um array diretamente.
A segunda opção para resolver o problema, é retornar um Hash e alterar a forma
que iteramos sobre o retorno no método livros:
biblioteca = Biblioteca.new
teste_e_design = Livro.new "Mauricio Aniche",
"123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9, 55
4.4. Como separar os livros por categoria: trabalhe com Hash
Casa do Código
:web_design
biblioteca.adiciona teste_e_design
biblioteca.adiciona web_design_responsivo
for categoria, livros in biblioteca.livros do
p categoria
for livro in livros do
p livro.valor
end
end
# => :testes
# => 60.9
# => :web_design
# => 70.9
A diferença é que o método for recebe dois argumentos, a chave e o valor do
hash. Em nosso exemplo, a chave é a categoria da estante de livros ( :testes,
por exemplo), e valor é um array com os livros desta categoria.
Os métodos values e flatten
Quando precisamos obter todos os valores de um determinado hash, indepen-
dente do container, utilizamos o método values (que retorna todos os valores do
hash dentro de um Array):
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
hash = { testes: teste_e_design, web_design: web_design_responsivo }
p hash.values # [teste_e_design, web_design_responsivo]
No caso da classe Biblioteca, nós guardamos conjuntos de livros dentro de
Array, sendo um Array para cada categoria. Quando os valores de um hash são
do tipo Array, o método values retornará um novo Array com vários Array
dentro, o que pode não ser um resultado muito interessante para trabalharmos, veja:
56
Casa do Código
Capítulo 4. Estruturas de dados
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
hash = { testes: [teste_e_design], web_design: [web_design_responsivo]}
p hash.values
# => [Autor: Mauricio Aniche, Isbn: 123454, Páginas: 247,
Categoria: testes],
[Autor: Tárcio Zemel, Isbn: 452565, Páginas: 189,
Categoria: web_design]
Precisamos que o retorno do método livros seja um único Array com to-
dos os livros existentes dentro da Biblioteca independente da categoria deles.
Podemos alcançar nosso objetivo utilizando o método flatten:
teste_e_design = Livro.new "Mauricio Aniche", "123454", 247, 60.9,
:testes
web_design_responsivo = Livro.new "Tárcio Zemel", "452565", 189, 70.9,
:web_design
hash = { testes: [teste_e_design], web_design: [web_design_responsivo]}