Rutas
/
Julia
Julia
/
Ejercicios
/
Sugerencias de la boutique
Sugerencias de la boutique

Sugerencias de la boutique

Ejercicio de aprendizaje

Introducción

Cualquiera que haya usado Python casi con toda seguridad ha usado listas por comprensión, que han sido un elemento central de la sintaxis de Python desde las primeras versiones.

Algo tan cómodo se abre camino poco a poco en otros lenguajes, incluido Julia.

Para quienes programan en Julia, las comprensiones son una opción y no una necesidad, ya que normalmente existen alternativas (broadcasting, funciones de orden superior, etc.).

Sin embargo, una comprensión suele ofrecer una forma sencilla, legible y eficiente de construir un array. Al final, usarlas es una cuestión de gusto personal, y de cómo te sientes respecto a Python frente a los lenguajes funcionales.

La sintaxis es en su mayor parte una copia directa de Python, pero con extensiones para arrays de más dimensiones.

Una sola variable

Muy al estilo de Python, incluida la cláusula if opcional.

julia> [x^2 for x in 1:3]
3-element Vector{Int64}:
 1
 4
 9
julia> [x^2 for x in 1:3 if isodd(x^2)]
2-element Vector{Int64}:
 1
 9

La forma de la salida depende de los detalles de la comprensión: normalmente la misma que la colección de entrada en los casos simples, pero aplanada a un Vector por una cláusula if.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x^2 for x in m]
2×3 Matrix{Int64}:
  1   4   9
 16  25  36
julia> [x^2 for x in m if isodd(x^2)] 
3-element Vector{Int64}:
  1
 25
  9

Varias variables, salida de tipo Vector

Igual que en Python, podemos tener varias cláusulas for con variables distintas, con colecciones de entrada iguales o diferentes.

julia> [x * y for x in 1:3 for y in 4:6]
9-element Vector{Int64}:
  4
  5
  6
  8
 10
 12
 12
 15
 18
julia> [x * y for x in 1:3 for y in 4:6 if isodd(x * y)]
2-element Vector{Int64}:
  5
 15

Esto equivale a bucles anidados. La salida es unidimensional, incluso con una matriz de entrada.

julia> m
2×3 Matrix{Int64}:
 1  2  3
 4  5  6
julia> [x*y for x in m for y in m]
36-element Vector{Int64}:
  1
  4
  2
  5
(truncated output...)

Varias variables, salida multidimensional

En la sección anterior vimos varias cláusulas for separadas solo por espacios.

En esta sección hay un solo for y las variables van separadas por comas.

julia> [(x, y) for x in 1:3, y in 4:6]
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)

Cada variable de la comprensión crea una nueva dimensión en la salida, con una entrada por cada combinación posible de las variables.

En el ejemplo anterior, x aumenta hacia abajo por las filas y y aumenta a lo ancho de las columnas. Se pueden usar más dimensiones, con las advertencias habituales sobre la legibilidad de la salida.

Expresiones generadoras

Las secciones anteriores se han centrado en la salida de tipo array, con la comprensión colocada entre corchetes [ ... ].

Cuando los corchetes se sustituyen por paréntesis ( ... ), ocurre algo distinto: obtenemos una generator expression: un iterador evaluado de forma perezosa que puede producir el siguiente valor cuando se le pide.

julia> g = ((x, y) for x in 1:3, y in 4:6)
Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}, var"#9#10"}(var"#9#10"(), Base.Iterators.ProductIterator{Tuple{UnitRange{Int64}, UnitRange{Int64}}}((1:3, 4:6)))
# Indexing fails with a generator, the entries don't exist yet
julia> g[1, 2]
ERROR: MethodError: no method matching getindex(::Base.Generator{Base.Iterators.ProductIterator{Tuple{UnitRange{…}, UnitRange{…}}}, var"#9#10"}, ::Int64, ::Int64)
# conversion to array
julia> collect(g)
3×3 Matrix{Tuple{Int64, Int64}}:
 (1, 4)  (1, 5)  (1, 6)
 (2, 4)  (2, 5)  (2, 6)
 (3, 4)  (3, 5)  (3, 6)
# generators are mainly designed for iteration
julia> [i * j for (i, j) in g]
3×3 Matrix{Int64}:
  4   5   6
  8  10  12
 12  15  18

Cuando el resultado de una comprensión se usa de inmediato para seguir procesando, un generador puede ser eficiente en memoria, ya que evita tener que almacenar un array intermedio grande.

Un generador usado como argumento de una función no necesita paréntesis adicionales.

# inefficient
julia> v = [x^2 for x in 1:1e6];
julia> sum(v)
3.333338333335e17
# better - use a generator
julia> sum(x^2 for x in 1:1e6)
3.3333383333312755e17

La sintaxis de los generadores es idéntica a la de las comprensiones, salvo por los corchetes que los rodean.

Los generadores también pueden resultar cómodos en los constructores de diccionarios.

julia> Dict(x => x^2 for x in 1:5)
Dict{Int64, Int64} with 5 entries:
  5 => 25
  4 => 16
  2 => 4
  3 => 9
  1 => 1

Instrucciones

Trabajas en una tienda de moda online. Se te ocurre la idea de una funcionalidad del sitio web en la que se sugieren conjuntos al usuario. Lo que interesa son los posibles conjuntos, sus precios y eliminar las opciones que no combinan.

Note

Aunque puede haber distintas formas de resolver los siguientes problemas, todos se pueden resolver con una comprensión.

1. Crea un artículo de ropa

Implementa clothingitem() para que reciba dos Tuple, uno de categories y otro de sus respectivas qualities. La función debe devolver un Dict con las categories como claves y las qualities como valores.

julia> categories = ("item_name", "price", "color", "base_color");

julia> qualities = ("Descriptive Name", 99.00, "Ochre Red", "red");

julia> clothingitem(categories, qualities)
Dict{String, Any} with 4 entries:
  "price"      => 99.0
  "item_name"  => "Descriptive Name"
  "base_color" => "red"
  "color"      => "Ochre Red"

Tu función debe poder manejar cualquier número de categories.

2. Sugiere combinaciones

Implementa get_combinations() para que reciba un Tuple de prendas superiores y un Tuple de prendas inferiores. La función debe devolver el cartesian product de los tuples como un array bidimensional (es decir, una Matrix). Cada entrada es una combinación (top, bottom) como un Tuple. Las prendas superiores cambian a lo largo de las filas y las inferiores, a lo largo de las columnas.

julia> tops = (
        Dict("item_name" => "Dress shirt"),
        Dict("item_name" => "Casual shirt")
        );

julia> bottoms = (
        Dict("item_name" => "Jeans"),
        Dict("item_name" => "Dress trousers")
       );

julia> get_combinations(tops, bottoms)
2×2 Matrix{Tuple{Dict{String, String}, Dict{String, String}}}:
 (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Jeans"))   (Dict("item_name"=>"Dress shirt"), Dict("item_name"=>"Dress trousers"))
 (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Jeans"))  (Dict("item_name"=>"Casual shirt"), Dict("item_name"=>"Dress trousers"))

3. Suma los precios de los conjuntos

Cada prenda de ropa tiene un campo price asociado, por lo que podría resultar útil poder comparar el precio total de los conjuntos. Implementa get_prices(), que recibe un array de combinaciones de prendas. La función debe devolver un array con la misma forma, con los precios de los conjuntos en sus posiciones respectivas.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combomatrix = get_combinations(tops, bottoms);

julia> get_prices(combomatrix)
2×2 Matrix{Int}::
 65  110
 50   95

julia> filteredmatrix = filter_clashing(combomatrix)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))

julia> get_prices(filteredmatrix)
1-element Vector{Int}:
 50

4. Filtra los conjuntos que no combinan

Cada prenda de ropa tiene un campo base_color. Usa este campo para eliminar todas las combinaciones en las que la prenda superior y la inferior tengan el mismo color base. Implementa filter_clashing() para que reciba un array de combinaciones de prendas. Devuelve un array unidimensional (es decir, un Vector) con las combinaciones válidas.

julia> tops = (
        Dict("item_name" => "Dress shirt", "base_color" => "blue", "price" => 35),
        Dict("item_name" => "Casual shirt", "base_color" => "black", "price" => 20)
       );

julia> bottoms = (
        Dict("item_name" => "Jeans", "base_color" => "blue", "price" => 30),
        Dict("item_name" => "Dress trousers", "base_color" => "black", "price" => 75)
       );

julia> combos = get_combinations(tops, bottoms);

julia> filter_clashing(combos)
1-element Vector{Tuple{Dict{String, Any}, Dict{String, Any}}}:
 (Dict("price" => 20, "item_name" => "Casual shirt", "base_color" => "black"), Dict("price" => 30, "item_name" => "Jeans", "base_color" => "blue"))
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Julia Exercism

¿Listo para empezar Sugerencias de la boutique?

Regístrate en Exercism para aprender y dominar Julia con 35 conceptos128 ejercicios y mentoría humana real, todo gratis.