2011-08-17 15 views
9

Mi chiedo se mi manca qualcosa di base che coinvolge la manipolazione del vettore. Diciamo che ho il seguente:Come si modifica una porzione di un vettore in Clojure?

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

Se voglio tornare il vettore [1 10 3 12 13] in Matlab, vorrei scrivere xs(idx) = values. In Clojure, c'è un modo primitivo per raggiungere questo? In questo momento sto usando la seguente funzione:

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

Grazie.

+0

Non posso offrire alcun codice oltre ai suggerimenti già forniti. 'assoc' _è_ la primitiva appropriata ma vuole che gli indici e i valori siano passati individualmente come si vede già. Puoi costruire una sequenza di coppie di valori di indice come fai tu e usare 'apply' o ricorsivamente associare usando' reduce' come suggerito da amalloy e mikera. Sotto il cofano la versione multi-indice del socio è ricorsiva comunque. Considero le opzioni 'reduce' più idiomatiche. –

+0

Penso che la tua soluzione sia praticamente la migliore. –

+2

'apply assoc' e' interleave' sono probabilmente la scelta migliore quando tutto ciò che si vuole fare è impostare in modo specifico un indice senza riguardo al suo valore precedente. La maggior parte delle volte sospetto che vorrete fare qualcosa di più complicato, e quindi questo "trucco" non funzionerà affatto; è per questo che ho suggerito di usare 'reduce', che è più generale. – amalloy

risposta

8

È un po 'imbarazzante perché hai diviso idx e values in due seq, quando sono concettualmente una mappa di indici di valori. Quindi, se mi permettete una piccola modifica creativa del formato dei dati:

(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 

Se si genera idx e values in qualche modo strano che non è conveniente per raggrupparli, è possibile raggrupparli in seguito con (map list idx values) e quindi utilizzare la mia implementazione xinto con quello.

+0

Considera l'uso di 'transient',' assoc! 'E' persistent! 'Qui. – seh

+3

@seh Uh, immagino che tu possa farlo, ma a stento sembra che valga la pena. Se il vettore iniziale o l'insieme di modifiche da apportare è piccolo, il tempo necessario per la transizione da/a un transiente supererà i vantaggi dell'utilizzo di uno. – amalloy

+0

o (valori idx zipmap) anziché (valori elenco elenco valori) – zmila

2

Impossibile trovare qualcosa di meglio.

Nelle funzioni di sequenza principale è replace, ma funziona sui valori, non sui tasti. Così,

(replace {9 2} x) 

sarebbe tornato

[2 10 11 12 13] 

Se avete intenzione di fare le cose relative matematica in Clojure, ho anche proporre di avere uno sguardo a Incanter. Ha un sacco di API per manipolare dati matematici.

3

probabilmente sarei uso reduce per questo:

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

Tuttavia, se si vuole veramente fare questo un sacco (Matlab-style), allora io suggerirei di creare alcune macro di supporto/funzioni per creare un po ' tipo di DSL per manipolazione vettoriale.

+0

Stavo cercando di seguire il codice di esempio ma sembrava che mancasse il vettore originale 'x'. Ho modificato l'esempio per essere la forma a tre argomenti di ridurre per chiarezza. –

Problemi correlati