Tracks
/
Julia
Julia
/
Ejercicios
/
Sugerencias de boutique
Sugerencias de boutique

Sugerencias de boutique

Ejercicio de aprendizaje

Introducción

Cualquiera que haya usado Python casi con seguridad ha usado comprensiones de arrays, que han sido parte central de la sintaxis de Python desde sus primeras versiones.

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

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

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

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

Una sola variable

Muy al estilo 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 es la misma que la de la colección de entrada en los casos simples, pero una cláusula if la aplana a un Vector.

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

Como en Python, podemos tener varias cláusulas for con variables distintas, y 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 cuando la entrada es una matriz.

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

La sección anterior describió varias cláusulas for separadas únicamente 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 para cada combinación posible de las variables.

En el ejemplo anterior, x aumenta a lo largo de las filas y y a lo largo de las columnas. Es posible usar más dimensiones, con las advertencias habituales sobre la legibilidad de la salida.

Expresiones generadoras

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

Cuando los corchetes se reemplazan por paréntesis ( ... ), pasa algo diferente: obtenemos una generator expression, un iterador de evaluación perezosa que puede producir el siguiente valor cuando se lo 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 el uso de memoria, ya que evita tener que almacenar un array intermedio grande.

Un generador que se usa 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 un generador es idéntica a la de una comprensión, salvo por los corchetes que la 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 en línea. Se te ocurre la idea de una funcionalidad del sitio web en la que se le 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 maneras 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 el 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 cantidad de categories.

2. Sugiere combinaciones

Implementa get_combinations() para que reciba un Tuple de prendas de arriba y un Tuple de prendas de abajo. La función debe devolver el cartesian product de las tuplas como un array bidimensional (es decir, una Matrix). Cada entrada es una combinación (top, bottom) como Tuple. Las prendas de arriba cambian al bajar por las filas y las prendas de abajo cambian al avanzar por 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, así que podría ser ú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 respectivas posiciones.

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 de arriba y la de abajo tienen 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 que pasan el filtro.

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 una pestaña nuevas
Julia Exercism

¿Todo listo para empezar Sugerencias de boutique?

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