2010-12-22 17 views
6

Per esempio, la parola "stack", voglio ottenere un array come:Qual è il modo migliore per dividere una stringa per ottenere tutte le sottostringhe da Ruby?

['s', 'st', 'sta', ... 'stack', 't', 'ta', ... , 'c', 'ck', 'k'] 

Ho fatto questo da tale codice:

def split_word(str) 
    result = [] 
    chas = str.split("") 
    len = chas.size 
    (0..len-1).each do |i| 
    (i..len-1).each do |j| 
     result.push(chas[i..j].join) 
    end 
    end 
    result.uniq 
end 

C'è modo migliore e più pulito per farlo? Grazie.

+0

Con o senza duplicati? –

+0

senza duplicati, grazie! –

+0

consiglio generale: meglio usare la mappa (funzionale) invece di seguire lo schema "init empty + iterate + push + return" (imperativo) – tokland

risposta

11
def split_word s 
    (0..s.length).inject([]){|ai,i| 
    (1..s.length - i).inject(ai){|aj,j| 
     aj << s[i,j] 
    } 
    }.uniq 
end 

E si può anche considerare l'utilizzo Set invece di Array per il risultato.

PS: Ecco un'altra idea, basata su prodotti di matrici:

def split_word s 
    indices = (0...s.length).to_a 
    indices.product(indices).reject{|i,j| i > j}.map{|i,j| s[i..j]}.uniq 
end 
+0

che bella soluzione! –

+0

risolta seconda soluzione dopo un suggerimento da parte dell'utente @steel –

2

Non penso.

Ecco il mio tentativo di versione:

def split_word(str) 
    length = str.length - 1 
    [].tap do |result| 
    0.upto(length) do |i| 
     length.downto(i) do |j| 
     substring = str[i..j] 
     result << substring unless result.include?(substring) 
     end 
    end 
    end 
end 
+0

Buono! Funziona e sembra più pulito. –

3

che avrei scritto:

def split_word(s) 
    0.upto(s.length - 1).flat_map do |start| 
    1.upto(s.length - start).map do |length| 
     s[start, length] 
    end 
    end.uniq 
end 

groups = split_word("stack") 
# ["s", "st", "sta", "stac", "stack", "t", "ta", "tac", "tack", "a", "ac", "ack", "c", "ck", "k"] 

Di solito è più chiaro e più compatto da utilizzare map (funzionale) al posto del modello init vuoto + each + append + return (obbligatorio).

+0

Sì, hai ragione tokland.Preferisco lo schema funzionale piuttosto che il modello imperativo. Grazie per il tuo suggerimento! E quale schema ritieni abbia le prestazioni migliori? –

+0

@ pake007: beh, ho detto che di solito è più veloce, ma qui non sono così sicuro a causa dell'appiattimento e della non-pigrizia degli array di Ruby. Ad ogni modo, non sudare per le prestazioni, la differenza è probabilmente minima. – tokland

0

In un secondo momento, ma questo è ciò che ho ottenuto riformattando il codice un po '.

def substrings(string) 
    siz = string.length 
    answer = [] 

    (0..siz-1).each do |n| 
    (n..siz-1).each do |i| 
     answer << string[n..i] 
    end 
    end 
    answer 
end 
2
def substrings(str) 
    output = [] 
    (0...str.length).each do |i| 
    (i...str.length).each do |j| 
     output << str[i..j] 
    end 
    end 
    output 
end 

questa è solo una versione ripulita del metodo e funziona con meno passaggi =)

2
def substrings(str) 
    (0...str.length).map do |i| 
    (i...str.length).each { |j| str[i..j]} 
    end 
end 

Solo un altro modo per farlo, che legge un po 'più chiaro per me.

Problemi correlati