Aparte de que los diccionarios son mutables y NamedTuple no, que NamedTuple se puede recuperar por posición y un poco de notación diferente, ¿hay otras diferencias significativas entre Diccionarios y NamedTuples en Julia? ¿Cuándo usar uno u otro?

Ellas parecen bastante similares:

# Definition
d  = Dict("k1"=>"v1", "k2"=>"v2")
nt = (k1="v1", k2="v2")

# Selection by specific key
d["k1"]
nt.k1

# Keys
keys(d)
keys(nt)

# Values
values(d)
values(nt)

# Selection by position
d[1] # error
nt[1]
1
Antonello 10 sep. 2018 a las 16:45

3 respuestas

La mejor respuesta

Piense en NamedTuple como un struct anónimo en Julia, no en un Dict. En particular, almacenar tipos heterogéneos en NamedTuple es tipo estable.

Tenga en cuenta que esto también es una diferencia importante en el pensamiento entre Python y Julia. En Julia, si desea que su código sea rápido, generalmente le importa la inferencia de tipos.

4
Bogumił Kamiński 10 sep. 2018 a las 14:50

Según preguntas similares sobre Python parece ... no. Las principales diferencias parecen ser la propiedad mutable / inmutable y que x.a es más legible y menos detallado que x [a] ...:

-2
Antonello 10 sep. 2018 a las 14:11

Una diferencia significativa en Julia es que un NamedTuple es de su propio tipo y, por lo tanto, el compilador puede especializarse en esa firma de tupla nombrada en particular, mientras que el enfoque del Diccionario debe buscar el valor de la clave. Además, cada valor de un NamedTuple puede ser un tipo diferente en sí mismo, lo que permite una mayor optimización y estabilidad de tipo más allá de lo que se puede lograr en un diccionario. Si lo cambiamos un poco más para que el tipo de diccionario sea heterogéneo de modo que sea del tipo Dict{Symbol,Any}, puede ver cómo aún puede ser de tipo estable.

d=Dict(:k1=>"v1",:k2=>2.0)
nt=(k1="v1",k2=2.0)

foo(x) = x[:k2]

Ahora, si una función usa este diccionario o tupla nombrada directamente, podemos ver el tipo de diccionario, el resultado no es estable, ya que el valor en el Diccionario solo puede garantizarse con el tipo de Any.

@code_warntype foo(d)

Body::Any
4 1 ─ %1 = invoke Base.ht_keyindex(_2::Dict{Symbol,Any}, :k2::Symbol)::Int64                                                                                                                                               │╻  getindex
  │   %2 = (Base.slt_int)(%1, 0)::Bool                                                                                                                                                                                     ││╻  <
  └──      goto #3 if not %2                                                                                                                                                                                               ││
  2 ─ %4 = %new(Base.KeyError, :k2)::KeyError                                                                                                                                                                              ││╻  Type
  │        (Base.throw)(%4)                                                                                                                                                                                                ││
  └──      $(Expr(:unreachable))                                                                                                                                                                                           ││
  3 ─ %7 = (Base.getfield)(x, :vals)::Array{Any,1}                                                                                                                                                                         ││╻  getproperty
  │   %8 = (Base.arrayref)(false, %7, %1)::Any                                                                                                                                                                             ││╻  getindex
  └──      goto #5                                                                                                                                                                                                         ││
  4 ─      $(Expr(:unreachable))                                                                                                                                                                                           ││
  5 ┄      return %8

Por otro lado, un NamedTuple puede ser de tipo estable. Debido a que la función conocía el campo, también se sabe que el tipo es Float64.

@code_warntype foo(nt)

Body::Float64
4 1 ─ %1 = (Base.getfield)(x, :k2)::Float64                                                                                                                                                                                     │╻ getindex
  └──      return %1
6
dberge 10 sep. 2018 a las 15:13