2011-08-17 17 views
9

Me pregunto si me estoy perdiendo algo básico relacionado con la manipulación de vectores. Digamos que tengo el siguiente:¿Cómo modifico una porción de un vector en Clojure?

(def xs [9 10 11 12 13]) 
(def idx [0 2]) 
(def values [1 3]) 

Si quiero devolver el vector [1 10 3 12 13] en Matlab, me gustaría escribir xs(idx) = values. En Clojure, ¿hay alguna forma primitiva de lograr esto? En este momento estoy usando la siguiente función:

(defn xinto [seq idx val] 
    (apply assoc seq (interleave idx val))) 

Gracias.

+0

No puedo ofrecer ningún código más allá de las sugerencias ya dadas. 'assoc' _es_ la primitiva apropiada pero quiere que los índices y valores pasen individualmente como ya se ve. Puedes construir una secuencia de pares de valores de índice como lo haces y usar 'apply' o recurrentemente hacer la asociación usando' reduce' como lo sugieren amalloy y mikera. Bajo el capó, la versión multi-valor de Assoc es recursiva de todos modos. Consideraría las opciones 'reducir' más idiomáticas. –

+0

Creo que su solución es bastante buena. –

+2

'apply assoc' y' interleave' son probablemente la mejor opción cuando todo lo que desea hacer es establecer específicamente un índice sin tener en cuenta su valor anterior. La mayor parte del tiempo sospecho que querrás hacer algo más complicado, y entonces este "truco" no funcionará en absoluto; es por eso que sugerí usar 'reduce', que es más general. – amalloy

Respuesta

8

Es un poco incómodo porque ha dividido idx y values en dos partes, cuando conceptualmente son un mapa de índices de valores. Así que si me permite una pequeña modificación creativa de su formato de datos:

(def x [9 10 11 12 13]) 
(def changes {0 1, 2 3}) 

(defn xinto [v changes] 
    (reduce (fn [acc [k v]] 
      (assoc acc k v)) 
      v 
      changes)) 

(xinto x changes) ;; gets the result you want 

Si genera idx y values de alguna manera extraña de que no es conveniente agrupar juntos, se pueden agrupar en otro momento con (map list idx values) y luego use mi implementación xinto con eso.

+0

Considera usar 'transient',' assoc! ', Y' persistent! 'Aquí. – seh

+3

@seh Uh, supongo que podrías hacer eso, pero parece que no vale la pena el esfuerzo. Si el vector inicial o el conjunto de cambios a realizar es pequeño, el tiempo necesario para la transición a/desde un transitorio será mayor que las ganancias de usar uno. – amalloy

+0

o (zipmap idx values) en lugar de (map list idx values) – zmila

2

No se pudo encontrar algo mejor.

En las funciones de secuencia de núcleo hay replace, pero funciona en valores, no en teclas. Así,

(replace {9 2} x) 

regresarían

[2 10 11 12 13] 

Si va a hacer las cosas relacionadas matemáticas en Clojure, también propongo que echar un vistazo a Incanter. Tiene muchas API para manipular datos matemáticos.

3

probablemente haría uso de este reduce:

(reduce 
    (fn [old [i v]] (assoc old i v)) 
    x 
    (map vector idx values)) 

Sin embargo, si usted realmente quiere hacer esto mucho (al estilo de Matlab), entonces me gustaría sugerir la creación de algunas macros helper/funciones para crear algunos tipo de DSL para la manipulación de vectores.

+0

Intenté seguir el código de ejemplo pero parecía que faltaba el vector original 'x'. Edité el ejemplo para que sea la forma de tres argumentos de reducir para mayor claridad. –

Cuestiones relacionadas