# -*- coding: utf-8 -*-
# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .jl
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: julia1.6 1.6.1
#     language: julia
#     name: julia1.6-1.6
# ---

# # Estruturas de dados
#
# Quando começarmos a trabalhar com muitos dados ao mesmo tempo, será conveniente para nós armazenar dados em estruturas como arrays ou dicionários (em vez de confiarmos apenas em variáveis).<br>
#
# Tipos de estruturas de dados abrangidos:
# 1. Tuples
# 2. Dicionários
# 3. Arrays
#
# <br>
# Como visão geral, os tuples e os arrays são sequências ordenadas de elementos (para que possamos indexar neles). Os dicionários e os arrays são ambos mutáveis.
# Explicaremos isto mais abaixo!

# ## Tuples
#
# We can create a tuple by enclosing an ordered collection of elements in `( )`.
#
# Syntax: <br>
# ```julia
# (item1, item2, ...)
# ```
#

meusanimaisfav = ("pinguins", "gatos", "Petauro")

# Podemos indexar neste tuple,

meusanimaisfav[1]

# mas como os tuples são imutáveis, não podemos atualizá-los

meusanimaisfav[1] = "otters"

# ## Agora em 1.0: NamedTuples
#
# Como podemos adivinhar, `NamedTuple`s são exatamente como `Tuple`s exceto que cada elemento adicionalmente tem um nome! Eles têm uma sintaxe especial usando `=` dentro de um tuple:
#
# ```julia
# (nome1 = item1, nome2 = item2, ...)
# ```

meusanimaisfav = (passaro = "pinguins", mamifero = "gato", marsupial = "Petauro")
# isso parece um dicionário ordenado mas imutável, ou não ?

# Como os regulares `Tuples`, `NamedTuples` são ordenados, para que possamos recuperar seus elementos através de indexação:

meusanimaisfav[1]

# Eles também acrescentam a habilidade especial de acessar valores por seu nome:

meusanimaisfav.passaro

# ## Dicionários
#
# Se tivermos conjuntos de dados relacionados uns aos outros, podemos optar por armazenar esses dados em um dicionário. Podemos criar um dicionário usando o `Dict()` que podemos inicializar como um dicionário vazio ou uma chave de armazenamento, pares de valores.
#
# Syntax:
# ```julia
# Dict(chave1 => valor1, chave2 => vslor2, ...)
# ```
#
# Um bom exemplo é uma lista de contatos, onde associamos nomes a números de telefone.

listadetel = Dict("Joana" => "867-5309", "Caça-Fantasmas" => "555-2368")

# Neste exemplo, cada nome e número é um par "chave" e "valor". Podemos pegar o número da Joana (um valor) usando a chave associada

listadetel["Joana"]

# Podemos acrescentar outra entrada a este dicionário da seguinte forma

listadetel["Filipe"] = "555-FILK"

# Vamos verificar como está a nossa lista telefônica agora...

listadetel

# Podemos excluir Filipe de nossa lista de contatos e simultaneamente obter seu número - usando `pop!`

pop!(listadetel, "Filipe")

listadetel

# Ao contrário dos tuples e arrays, os dicionários não são encomendados. Portanto, não podemos indexar neles.

listadetel[1]

# No exemplo acima, `julia` acha que você está tentando acessar um valor associado à chave `1`.

# ## Arrays
#
# Ao contrário dos tuples, os arrays são mutáveis. Ao contrário dos dicionários, os arrays contêm coleções ordenadas. <br>
# Podemos criar um array, encerrando essa coleção em `[ ]`.
#
# Syntax: <br>
# ```julia
# [item1, item2, ...]
# ```
#
#
# Por exemplo, podemos criar uma matriz para acompanhar meus amigos

amigos = ["Filipe", "Monalisa", "Ana", "Fernando", "Rodrigo"]

# O `1` no `Array{String,1}` significa que este é um vetor unidimensional. Um `Array{String,2}` seria uma matriz 2d, etc. A `String` é o tipo de cada elemento.

# ou para armazenar uma sequência de números

fibonacci = [1, 1, 2, 3, 5, 8, 13]

mixture = [1, 1, 2, 3, "Rodrigo", "Rubens"]

# Uma vez que tenhamos um array, podemos pegar pedaços individuais de dados de dentro desse array, indexando-os ao array. Por exemplo, se quisermos o terceiro amigo listado em `amigos`, escrevemos

amigos[3]

# Podemos usar a indexação para editar um elemento existente de um array

amigos[3] = "Francisco"

# Sim, Julia é uma indexação baseada em 1, não em 0 como Python.  As guerras são travadas por questões menores. Eu tenho um amigo com a sabedoria de Salomão que propõe resolver isto de uma vez por todas com ½ 😃

# Também podemos editar o array usando as funções `push!` e `pop!. `push!` adiciona um elemento ao final de um array e `pop!` remove o último elemento do array
#
# Podemos adicionar outro número à nossa seqüência fibonnaci

push!(fibonacci, 21)

# e então remova-o

pop!(fibonacci)

fibonacci

# Até agora eu dei exemplos de apenas arrays 1D de escalares, mas os arrays podem ter um número arbitrário de dimensões e também podem armazenar outros arrays. 
# <br><br>
# Por exemplo, os seguintes são arrays de arrays:

favoritos = [["kebab", "chocolate", "ovos"],["pinguins", "gatos", "pentauro"]]

numeros = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]

# Abaixo estão exemplos de arrays 2D e 3D povoada com valores aleatórios.

rand(4, 3)

rand(4, 3, 2)

# Seja cuidadoso quando quiser copiar arrays!

fibonacci

mesmosnum = fibonacci

mesmosnum[1] = 404

fibonacci

# Editando `mesmosnum` faz com que `fibonacci` seja atualizado também!
#
# No exemplo acima, na verdade não fizemos uma cópia de `fibonacci`. Acabamos de criar uma nova maneira de acessar as entradas no array vinculado a `fibonacci`.
#
# Se quisermos fazer uma cópia do array vinculado a `fibonacci`, podemos usar a função `copy`.

# Primeiro, restaurar os fibonacci
fibonacci[1] = 1
fibonacci

mesmosnum = copy(fibonacci)

mesmosnum[1] = 404

fibonacci

# Neste último exemplo, fibonacci não foi atualizado. Portanto, vemos que os arrays ligados a `mesmosnum` e `fibonacci` 
# são distintos.

# ### Exercícios
#
# #### 3.1 
# Crie um array, `a_ray`, com o seguinte código:
#
# ```julia
# a_ray = [1, 2, 3]
# ```
#
# Adicione o número `4` ao final desta matriz e, em seguida, remova-o.

a_ray = [1, 2, 3];
push!(a_ray, 4);
println(a_ray)
pop!(a_ray);
println(a_ray)

# + editable=false hide_input=true nbgrader={"checksum": "8dde7e020bc07c5762194abf5c72285c", "grade": true, "grade_id": "cell-a6b20b78fbfeb449", "locked": true, "points": 1, "schema_version": 1, "solution": false}
@assert a_ray == [1, 2, 3]
# -

# #### 3.2 
# Tente adicionar "Emergência" como chave para `listadetel` com o valor `string(911)` com o seguinte código
# ```julia
# listadetel["Emergencia"] = 911
# ```
#
# Por que isso não funciona?

listadetel["Emergencia"] = 911

# #### 3.3 
#
# Crie um novo dicionário chamado `tel_flex` que tem o número da Joana armazenado como um número inteiro e o número dos Caça-Fantasmas armazenado como uma cadeia com o seguinte código
#
# ```julia
# tel_flex = Dict("Joana" => 8675309, "Caça-Fantasmas" => "555-2368")
# ```

tel_flex = Dict("Joana" => 8675309, "Caça-Fantasmas" => "555-2368")

@assert tel_flex == Dict("Joana" => 8675309, "Caça-Fantasmas" => "555-2368")

# #### 3.4 
# Acrescente a chave "Emergencia" com o valor `190` (um número inteiro) para `tel_flex`.

tel_flex["Emergencia"] = 190

@assert haskey(tel_flex, "Emergencia")

@assert tel_flex["Emergencia"] == 190

# #### 3.5 
# Por que podemos adicionar um número inteiro como um valor a `tel_flex` mas não a `listadetel`? Como poderíamos ter inicializado `listadetel` para que aceitasse inteiros como valores?

Dict{String, Int64}()
# Cria um dicionário vazio atribuindo a tipagem dos dados neste inicialização

# Por favor, clique no botão `Validate` no topo, após a conclusão do exercício

StarcoderdataJupyterScriptsDedupFiltered