Per quanto ne so, il risultato diCome uniq un caso gamma insensibile
["a", "A"].uniq
è
["a", "A"]
La mia domanda è:
Come faccio a fare [ "a" , "A"]. Uniq dammi ["a"] o ["A"]
Per quanto ne so, il risultato diCome uniq un caso gamma insensibile
["a", "A"].uniq
è
["a", "A"]
La mia domanda è:
Come faccio a fare [ "a" , "A"]. Uniq dammi ["a"] o ["A"]
Basta rendere il caso coerente per primo.
esempio:
["a","A"].map{|i| i.downcase}.uniq
Edit: Se come mikej suggerisce, gli elementi restituiti devono essere esattamente lo stesso come nella matrice originale, allora questo lo farà per voi:
a.inject([]) { |result,h| result << h unless result.map{|i| i.downcase}.include?(h.downcase); result }
Modifica2 Soluzione che dovrebbe soddisfare mikej :-)
downcased = []
a.inject([]) { |result,h|
unless downcased.include?(h.downcase);
result << h
downcased << h.downcase
end;
result}
["a", "A"].map{|x| x.downcase}.uniq
=> ["a"]
o
["a", "A"].map{|x| x.upcase}.uniq
=> ["A"]
Ack! Picchiato! – Codebeef
Una soluzione più generale (anche se non il più efficiente):
class EqualityWrapper
attr_reader :obj
def initialize(obj, eq, hash)
@obj = obj
@eq = eq
@hash = hash
end
def ==(other)
@eq[@obj, other.obj]
end
alias :eql? :==
def hash
@hash[@obj]
end
end
class Array
def uniq_by(eq, hash = lambda{|x| 0 })
map {|x| EqualityWrapper.new(x, eq, hash) }.
uniq.
map {|x| x.obj }
end
def uniq_ci
eq = lambda{|x, y| x.casecmp(y) == 0 }
hash = lambda{|x| x.downcase.hash }
uniq_by(eq, hash)
end
end
Il metodo uniq_by
prende un lambda che controlla l'uguaglianza, e un lambda che restituisce un hash e rimuove gli oggetti duplicati come definito da tali dati.
Implementato in aggiunta a questo, il metodo uniq_ci
rimuove i duplicati di stringa utilizzando confronti senza distinzione tra maiuscole e minuscole.
è possibile creare una mappatura (hash) tra il caso normalizzato (ad es.downcased) i valori e il valore effettivo e poi prendere solo i valori del hash:
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element ; h }\
.values
seleziona l'ultima occorrenza di una parola data (case insensitive):
["A", "b", "C"]
se si desidera la prima occorrenza :
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element unless h[element.downcase] ; h }\
.values
+1 Molto intelligente. – DanSingerman
Un po 'più efficiente e modo è quello di fare uso di chiavi uniq in hash, in modo da controllare questo:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] = j; hash}.values
tornerà l'ultimo elemento, in questo caso
["A"]
mentre usando || = operatore assegnazione:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] ||= j; hash}.values
tornerà primo elemento, in questo caso
["a"]
in particolare per i big Arrays, dovrebbe essere più veloce come non cerchiamo l'array ogni volta utilizzando include?
applausi ...
Se si utilizza ActiveSupport, è possibile utilizzare uniq_by. Non influisce sul caso dell'output finale.
['A','a'].uniq_by(&:downcase) # => ['A']
C'è un altro modo per farlo. Puoi effettivamente passare un blocco a uniq
o uniq!
che può essere utilizzato per valutare ciascun elemento.
["A", "a"].uniq { |elem| elem.downcase } #=> ["A"]
o
["A", "a"].uniq { |elem| elem.upcase } #=> ["A"]
In questo caso, però, tutto sarà case insensitive così sarà sempre tornare la matrice ["A"]
Ottima risposta. Nota che una variazione leggermente più corta è '[" A "," a "]. Uniq (&: downcase)'. – antinome
@antinome Molto più leggibile. –
Questa dovrebbe essere la risposta accettata ... –
Mentre questo avrebbe funzionato per l'esempio dato se la lista fosse qualcosa di simile ["Hello", "HELLO"] quindi ["Hello", "HELLO"]. Map {| i | i.downcase} .uniq restituirebbe "[hello"] che non corrisponde a nessuna delle stringhe nell'elenco originale. – mikej
La soluzione modificata è buona, tranne che costruirà la lista downcased usando result.map {| i | i.downcase} più volte (una volta per ogni elemento nell'elenco originale), quindi forse eseguirlo una volta come istruzione separata e memorizzare in una variabile temporanea se l'elenco è di grandi dimensioni. – mikej
La soluzione di @Eric C è molto più semplice. – depquid