Esiste un idioma per un ciclo che esegue un blocco di istruzioni tra le iterazioni? (In Ruby in particolare)

4

Spesso ho bisogno di fare alcune operazioni in un ciclo e alcune altre operazioni tra le iterazioni. Un semplice esempio potrebbe essere la raccolta di parole da un array in una stringa, digitate all'indietro e separate da virgole. C'è un idioma o supporto linguistico per questo in qualsiasi lingua? (Per ora sono principalmente interessato a Ruby.)

Di solito faccio qualcosa di simile

a = ['foo', 'bar', 'baz']
s = ''
n = a.size - 1
i = 0
loop do
  s << a[i].reverse
  break if i == n
  s << ', '
  i += 1
end

Ma non conosco alcun modo per salvare questa mezza iterazione se si utilizza un iteratore rubino:

s = ''
['foo', 'bar', 'baz'].each do |w|
  s << w.reverse
  # ???
end
    
posta Alexey 26.02.2013 - 21:50
fonte

3 risposte

5

Questo è chiamato il problema di loop-and-a-half. Hai descritto una soluzione popolare.

Le persone che si trovano nella programmazione funzionale risolvono molte istanze con una funzione chiamata di solito reduce , che prende una lista ed esegue un'operazione binaria per ogni elemento ma la prima con il risultato del calcolo precedente, e la valore successivo. Questa funzione è disponibile in Ruby con entrambi i nomi inject e reduce . Vedi link per ulteriori informazioni.

    
risposta data 26.02.2013 - 23:23
fonte
0

Ecco come puoi farlo in haskell:

let a = ["foo", "bar", "baz"]  --I've defined my "a" just like you defined it
Data.List.intercalate "," (map reverse a)  --here's the call that does what you want
"oof,rab,zab"  --this is the output

Il codice tra parentesi chiama la funzione reverse su ogni elemento di "a" (ad esempio: "foo" diventa "oof"). Ne prendi il risultato, e nella funzione un'altra concateni gli elementi insieme a "," tra di loro.

Ecco la cosa fondamentale da portare via qui: A volte hai funzioni che cambiano ogni elemento e restituiscono un altro elenco (es: map inverte ogni elemento, ma restituisce comunque una lista). Altre volte hai funzioni che prendono una lista e restituiscono un elemento (es: intercalate genererà una stringa fuori dall'elenco di stringhe che passi dentro).

Questi sono due passaggi separati e il tuo codice sarà più facile da riutilizzare se li tieni separati.

So che a Ruby non si risponde, ma spero che sia un po 'utile.

    
risposta data 27.02.2013 - 00:15
fonte
0

Sfortunatamente, non c'è nessun intercalate come nella risposta di @ tieTYT in ruby. Array#reduce può essere utilizzato ma - ad es. nel tuo esempio: devi tenere d'occhio l'ordine degli elementi (inversione del accumulatore memo ).
un esempio in ruby potrebbe apparire come questo:

arr = ["foo", "bar", "baz", "goo"]
puts arr.inspect
red = arr.reduce {|memo, item, err|
    "#{memo == arr.first ? memo.reverse : memo}, #{item.reverse}" 
}
puts red # -> oof, rab, zab, oog

il tuo esempio - unendo gli elementi di un array insieme in una stringa - può essere facilmente realizzato con Array#map seguito da Array#join (join è come l'intercalato di haskell, ma non accetta un blocco in ruby) come:

arr.map{|ele| ele.reverse}.join(", ")

dopo il tuo commento a @btilly:
IMHO, entrambi sembrano accettabili come one-liner, ad es. erb, anche se il secondo è chiaramente più leggibile.

<%= arr.reduce{|memo, item| "#{memo == arr.first ? memo.reverse : memo}, #{item.reverse}" } %>
<%= arr.map{|ele| ele.reverse}.join(", ") %>

in ogni caso puoi sempre assegnare il risultato a una variabile a monte.

    
risposta data 27.02.2013 - 09:56
fonte

Leggi altre domande sui tag