2011-11-20 15 views
8

Tengo un vector vEn clojure, cómo aplicar una función a los elementos seleccionados en un vector [gran]

(def v [1 2 5 8 4 3 8 9 3]) 

quiero aplicar la función myfn

(defn myfn [x] (+ 1 x)) 

a los elementos seleccionados que yo sus índices han idx

(def idx [3 5]) 

que he visto How do I modify a portion of a vector in Clojure? y no es exactamente lo que necesito.

Al igual que lo que se hace en MATLAB

v = [1 2 5 8 9 3]; 
idx = [3 5]; 
v(idx) = myfn(v(idx)); 
+0

lo siento, @yoda, ahora lo es. – Ali

Respuesta

9

vectores en clojure son asociativos, por lo que puede hacer algo como esto: (reduce #(update-in %1 [%2] myfn) v idx)

3

Actualizado porque malinterpretado la pregunta.

Aquí hay otra solución:

(apply assoc v (mapcat #(vector % (myfn (v %))) idx)) 

, es decir, construir una lista de argumentos de pares índice/nuevo valor a assoc. Creo que las soluciones de mange probablemente sean mejores.


original, solución incorrecta

No se olvide que el vector v es en sí mismo una función de sus índices. Por lo tanto:

(map myfn (map v idx)) 

o:

(->> idx (map v) (map myfn)) 

o:

(map (comp myfn v) idx) 

Estoy seguro de que hay también una respuesta muy inteligente que implica juxt :)

+1

Esto devolverá los índices modificados como un nuevo seq en lugar de actualizarlos dentro del vector original. – mange

+0

Vaya. La pregunta no especifica el resultado, por lo que fue fácil malinterpretar. –

2

usted menciona "un [ vector grande ", ¿te preocupa el rendimiento? Es posible que desee obtener información sobre transients:

(persistent! 
    (reduce (fn [v i] (assoc! v i (myfn (get v i)))) 
      (transient v) 
      idx)) 

O, si usted prefiere el estilo de bucle, esto hace lo mismo:

(loop [v (transient v), [i & is :as idx] idx] 
    (if (empty? idx) 
    (persistent! v) 
    (recur (assoc! v i (myfn (get v i))) is))) 
+0

Esto es ciertamente superior al actualizar muchos índices. ¿Cuál es el costo de 'transient' /' persistent! '? Supongo que para una pequeña cantidad de índices esto tendría un poco más de sobrecarga. – mange

+0

Se anuncian como O (1), y parecen ser bastante rápidos.El costo es mayor en las restricciones del código: debe usar un conjunto diferente de primitivos y no puede permitir que otros subprocesos accedan a los datos entre 'transient' y' persistent! '. Pero los transitorios son una buena combinación para un pequeño fragmento de código como este que realiza múltiples ediciones de la estructura de datos en un bucle. –

+0

Sí, 'O (1)' solo significa una sobrecarga constante, tan despreciable para un gran número de mutaciones, pero quizás significativo para números más pequeños. Nunca he usado transitorios, pero parecen súper útiles como este. – mange

0
(let [sidx (set idx)] 
    (vec      ;(sidx i) 
    (map-indexed (fn [i x] (if (contains? sidx i) (myfn x) x)) v))) 
+0

muy muy lento. – BLUEPIXY

Cuestiones relacionadas