MC-102 — Aula 15
Decomposicao de problemas
Quando o ChatGPT nao consegue resolver o seu problema de uma vez só.
dados = le()
saida = processa(dados)
imprime(saida)
variacoes:
leituras complicadas - quebrando em 2 ou mais
dados1 = le1()
dados2 = le2()
saida = processa(dados1, dados2)
imprime(saida)
processamento complicado, quebrando em varios sequenciais
dados = le()
resultados1 = processa1(dados)
resultados2 = processa2(resultados1)
imprime(resultados2)
loop para ler dados novos e processa-los
dados_gerais = legeral()
dados_novos = le_novos()
while tem_dados(dados_novos):
resultado = processa(dados_gerais, dados_novos)
imprime(resultado)
dados_novos = le_novos()
http://www.highwoodsbrewing.com/ibu.php
leia os dados do usuario
leia a tabela da pagina
obtenha o valor de U da tabela.
faca as contas para a quantidade de lupulo
imprima
escreva uma funcao que le numa linha de dados, o IBU, o alpha acid, o volume, o biol gravity e o boil time. Retorne uma tupla com esses valores
def ler_dados(linha):
# Divide a linha em partes usando espaços como delimitadores
partes = linha.split()
# Converte cada parte para o tipo apropriado
ibu = float(partes[0])
alpha_acid = float(partes[1])
volume = float(partes[2])
boil_gravity = float(partes[3])
boil_time = int(partes[4])
# Retorna uma tupla com os valores
return (ibu, alpha_acid, volume, boil_gravity, boil_time)
ibu,aa,vol,bg,bt = ler_dados()
a pagina http://www.highwoodsbrewing.com/ibu.php contem uma tabela (a primeira tabele). Leia a pagina e retorne a tabela como uma matrix de numeros
resposta
import requests
from bs4 import BeautifulSoup
def extrair_tabela_como_matriz(url):
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# Encontrar a primeira tabela
table = soup.find('table')
matriz = []
# Iterar sobre as linhas da tabela
for row in table.find_all('tr'):
linha = []
# Iterar sobre as colunas da linha
for cell in row.find_all(['td', 'th']):
# Converter o texto da célula para float se possível
try:
linha.append(float(cell.get_text(strip=True)))
except ValueError:
linha.append(cell.get_text(strip=True))
matriz.append(linha)
return matriz
# URL da página
url = "http://www.highwoodsbrewing.com/ibu.php"
tabela = extrair_tabela_como_matriz(url)
Ele retorna uma lista de linhas como a matriz!!
no programa acima, o primeiro elemento da primeira linha nao é um numero. é um string. subsitutia esse string por algum numero e retorne uma matriz numpy
def extrair_tabela_como_matriz(url):
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
# Encontrar a primeira tabela
table = soup.find('table')
matriz = []
# Iterar sobre as linhas da tabela
for row in table.find_all('tr'):
linha = []
# Iterar sobre as colunas da linha
for cell in row.find_all(['td', 'th']):
# Converter o texto da célula para float se possível
try:
linha.append(float(cell.get_text(strip=True)))
except ValueError:
linha.append(cell.get_text(strip=True))
matriz.append(linha)
return matriz
testar
Dado uma matriz numpy onde a primeira linha contem numeros que indicam o gravity boil das colunas correspondentes, e a primeira coluna contem os numeros que indicam o boil time das linhas correspondentes. Escreva uma funcao que dado a matriz descrita, o valor do boil gravity e o valor do boil time retorna o valor correspondente a essa coluna e linha da matriz
import numpy as np
def obter_valor_correspondente(matriz, boil_gravity, boil_time):
# Extrair a primeira linha e a primeira coluna
primeira_linha = matriz[0, :]
primeira_coluna = matriz[:, 0]
# Encontrar os índices correspondentes
try:
indice_coluna = np.where(primeira_linha == boil_gravity)[0][0]
indice_linha = np.where(primeira_coluna == boil_time)[0][0]
except IndexError:
raise ValueError("Boil gravity ou boil time não encontrados na matriz.")
# Retornar o valor correspondente na matriz
return matriz[indice_linha, indice_coluna]
# Exemplo de uso
matriz = np.array([
[0, 1.030, 1.040, 1.050],
[30, 20.0, 30.0, 40.0],
[60, 25.0, 35.0, 45.0],
[90, 30.0, 40.0, 50.0]
])
boil_gravity = 1.040
boil_time = 60
valor = obter_valor_correspondente(matriz, boil_gravity, boil_time)
testar
ibu,aa,vol,bg,bt = ler_dados()
url = "http://www.highwoodsbrewing.com/ibu.php"
tabela = extrair_tabela_como_matriz(url)
U = obter_valor_correspondente(tabela, bg, bt)
A palavra é interpolar.
Dado uma matriz numpy onde a primeira linha contem numeros que indicam o gravity boil das colunas correspondentes, e a primeira coluna contem os numeros que indicam o boil time das linhas correspondentes. O gravity boil é crescente da esquerda para a direira e o bol time é crescente de cima para baixo na matriz. Escreva uma funcao que dado a matriz descrita, o valor do boil gravity e o valor do boil time retorna o valor correspondente a essa coluna e linha da matriz. Se o valor do gravity boil e/ou do boil time nao estiverem na matriz, faca a interpolaçao aproproada
import numpy as np
def find_nearest(array, value):
array = np.asarray(array)
idx = (np.abs(array - value)).argmin()
return idx
def interpolate(x0, x1, y0, y1, x):
return y0 + (y1 - y0) * (x - x0) / (x1 - x0)
def get_value_from_matrix(matrix, gravity_boil, boil_time):
# Extrair os valores de gravity boil (primeira linha) e boil time (primeira coluna)
gravity_boil_values = matrix[0, 1:]
boil_time_values = matrix[1:, 0]
data_matrix = matrix[1:, 1:]
# Encontrar os índices mais próximos para gravity_boil e boil_time
gravity_boil_idx = find_nearest(gravity_boil_values, gravity_boil)
boil_time_idx = find_nearest(boil_time_values, boil_time)
# Verificar se os valores estão exatamente na matriz
exact_gravity = gravity_boil_values[gravity_boil_idx] == gravity_boil
exact_boil_time = boil_time_values[boil_time_idx] == boil_time
if exact_gravity and exact_boil_time:
return data_matrix[boil_time_idx, gravity_boil_idx]
# Interpolação para gravity_boil
if not exact_gravity:
if gravity_boil < gravity_boil_values[0]:
gravity_boil_idx = 0
elif gravity_boil > gravity_boil_values[-1]:
gravity_boil_idx = len(gravity_boil_values) - 1
else:
if gravity_boil > gravity_boil_values[gravity_boil_idx]:
gravity_boil_idx1 = gravity_boil_idx
gravity_boil_idx2 = gravity_boil_idx + 1
else:
gravity_boil_idx1 = gravity_boil_idx - 1
gravity_boil_idx2 = gravity_boil_idx
gravity_boil1 = gravity_boil_values[gravity_boil_idx1]
gravity_boil2 = gravity_boil_values[gravity_boil_idx2]
# Interpolação para boil_time
if not exact_boil_time:
if boil_time < boil_time_values[0]:
boil_time_idx = 0
elif boil_time > boil_time_values[-1]:
boil_time_idx = len(boil_time_values) - 1
else:
if boil_time > boil_time_values[boil_time_idx]:
boil_time_idx1 = boil_time_idx
boil_time_idx2 = boil_time_idx + 1
else:
boil_time_idx1 = boil_time_idx - 1
boil_time_idx2 = boil_time_idx
boil_time1 = boil_time_values[boil_time_idx1]
boil_time2 = boil_time_values[boil_time_idx2]
# Se ambos os valores precisam de interpolação
if not exact_gravity and not exact_boil_time:
z11 = data_matrix[boil_time_idx1, gravity_boil_idx1]
z12 = data_matrix[boil_time_idx1, gravity_boil_idx2]
z21 = data_matrix[boil_time_idx2, gravity_boil_idx1]
z22 = data_matrix[boil_time_idx2, gravity_boil_idx2]
z1 = interpolate(gravity_boil1, gravity_boil2, z11, z12, gravity_boil)
z2 = interpolate(gravity_boil1, gravity_boil2, z21, z22, gravity_boil)
result = interpolate(boil_time1
Eu acho que não.
Mas se os cupons fossem do tipo, “ganhe x% de desconte nesta compra” (desconto fixo e sem limite) ai havera uma solucao simples. Pegue o cupom com maior desconto e use-o na maior compra, o proximo maior desconto na 2a maior compra e assim por diante.
Mas no caso de cupons com limite no desconto, nao esta claro (para mim) que haja algum truque simples. Por que? Porque um cupom com desconto maior mas com limite menor pode ser pior (dependendo da compra) que um com desconto menor mais limite maior.
dados = le()
compras = gera_compras(dados)
cupons = gera_cupons(dados)
combinacoes = gera_combinacoes(compras, cupons)
descontos = []
for c in combinacoes:
x = computa_desconto_total(c)
descontos.append(x)
ordenado = sorted(descontos, reverse=True)
print(ordenado[0])
dado essa especificacao:
Como entrada, o seu programa deve receber 9 linhas com os valores de Q1, X1, Z1, Q2, X2, Z2, Q3, X3 e Z3, nessa ordem. Após isso, o seu programa deve receber uma linha com o número de compras n, seguido de n linhas com números que indicam o valor de cada uma dessas n compras. O i-ésimo valor lido indica a compra de índice i.
escreva uma funcao que le os dados e retorna uma tupla com os valores lidos de Q1 a Z3, e uma lista dos valores das compras. Leia os dados do arquivo a.txt
def ler_entrada_arquivo(caminho_arquivo):
with open(caminho_arquivo, 'r') as file:
linhas = file.readlines()
# Ler os valores de Q1, X1, Z1, Q2, X2, Z2, Q3, X3 e Z3
Q1 = int(linhas[0].strip())
X1 = float(linhas[1].strip())
Z1 = float(linhas[2].strip())
Q2 = int(linhas[3].strip())
X2 = float(linhas[4].strip())
Z2 = float(linhas[5].strip())
Q3 = int(linhas[6].strip())
X3 = float(linhas[7].strip())
Z3 = float(linhas[8].strip())
# Ler o número de compras
n = int(linhas[9].strip())
# Ler os valores das compras
compras = []
for i in range(10, 10 + n):
compras.append(float(linhas[i].strip()))
# Retornar uma tupla com os valores lidos e a lista de compras
return (Q1, X1, Z1, Q2, X2, Z2, Q3, X3, Z3), compras
Dado uma lista de numeros e uma lista de stings. vamos chamar de uma atribuicao uma lista de tuplas onde o primeiro componente vem da 1a lista e o segundo componente vem da segunda lista. Dado as 2 listas mencionadas, gere uma funcao que gera uma lista com todos as possivies atribuicoes entre essas 2 listas
from itertools import product
def generate_assignments(numbers, strings):
return list(product(numbers, strings))
# Exemplo de uso
numbers = [1, 2, 3]
strings = ['a', 'b', 'c']
assignments = generate_assignments(numbers, strings)
for assignment in assignments:
print(assignment)
Eu nao fui claro. Uma atribuicao é uma lista de todas as combinacoes entre numero e strings, onde cada numeor e cada string so aparece em uma tupla. Eu quero a lista de todas aas atribuicoes. Ou seja uma lista de lista de tuplas
from itertools import permutations
def generate_all_assignments(numbers, strings):
if len(numbers) != len(strings):
raise ValueError("The two lists must have the same length")
all_assignments = []
for perm in permutations(strings):
assignment = list(zip(numbers, perm))
all_assignments.append(assignment)
return all_assignments
# Exemplo de uso
numbers = [1, 2, 3]
strings = ['a', 'b', 'c']
assignments = generate_all_assignments(numbers, strings)
for assignment in assignments:
print(assignment)
Esta solucao esta melhor. mas a lista de numeros e de strings NAO necessariamente precisam ter o mesmo tamanho. Por favor redefina a funcao de tal forma que as duas listas nao tenham que ser do mesmo tamanho
from itertools import permutations, combinations
def generate_all_assignments(numbers, strings):
if len(numbers) > len(strings):
all_combinations = combinations(numbers, len(strings))
all_assignments = []
for comb in all_combinations:
for perm in permutations(comb):
assignment = list(zip(perm, strings))
all_assignments.append(assignment)
else:
all_combinations = combinations(strings, len(numbers))
all_assignments = []
for comb in all_combinations:
for perm in permutations(comb):
assignment = list(zip(numbers, perm))
all_assignments.append(assignment)
return all_assignments
# Exemplo de uso
numbers = [1, 2, 3, 4]
strings = ['a', 'b']
assignments = generate_all_assignments(numbers, strings)
for assignment in assignments:
print(assignment)
OK. Na minha opiniao a parte dificil ja foi resolvida - gerar todas as combinacoes entre compras e cupons. Para calcular o desconto total, eu tenho que olhar para cada par compra/cupom e somar todos os descontos de uma combinacao.
def computa_desconto_total(c):
total = 0.0
for compra, cupon in c:
desc = desconto(compra, cupon)
total = total + desc
return total
Finalmente para computar o desconto de uma compra com um cupom eu tenho que saber o que é uma compra (como ela esta representada) e o que é um cupom (como ele esta representado)
compra pode ser o valor da compra 100.00
ou compra pode ser o indice para uma lista com as compras [700.0, 563.45, 112.0, 145.3 …]
cupom pode ser uma tupla (1, X1, Z1) que indica que é um cupom do tipo 1, com os valores correspondentes de X1 e Z1.
ou pode ser um indice para uma lista com todos os cupons [(1, X1, Z1),(1, X1, Z1),(2, X2, Z2)…]
Como no final nos precisamos associar uma compra pela ordem e nao pelo valor com um cupom acho que é mais interessante que a compra seja um indice para a lista de valores. O cupom pode ser a tupla direto.