Por lo que yo sé, el resultado deCómo UniQ un caso gama insensibles
["a", "A"].uniq
se
["a", "A"]
Mi pregunta es:
¿Cómo hago [ "a" , "A"]. Uniq dame ya sea ["a"] o ["A"]
Por lo que yo sé, el resultado deCómo UniQ un caso gama insensibles
["a", "A"].uniq
se
["a", "A"]
Mi pregunta es:
¿Cómo hago [ "a" , "A"]. Uniq dame ya sea ["a"] o ["A"]
Simplemente haz que el caso sea consistente primero.
por ejemplo:
["a","A"].map{|i| i.downcase}.uniq
Editar: Si como mikej sugiere, los elementos devueltos debe ser exactamente el mismo que en la matriz original, entonces esto va a hacer eso por usted:
a.inject([]) { |result,h| result << h unless result.map{|i| i.downcase}.include?(h.downcase); result }
Edit2 Solución que debería satisfacer 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! ¡Golpeado! – Codebeef
Una solución más general (aunque no el más eficiente):
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
El método uniq_by
toma un lambda que verifica la igualdad, y un lambda que devuelve una hash, y elimina los objetos duplicados según lo definido por esos datos.
Implementado además de eso, el método uniq_ci
elimina los duplicados de cadenas mediante comparaciones insensibles a mayúsculas y minúsculas.
puede crear un mapeo (hash) entre la caja normalizada (p. Ej.downcased) los valores y el valor real y luego tomar sólo los valores de hash:
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element ; h }\
.values
selecciona la última ocurrencia de una palabra dada (mayúsculas y minúsculas):
["A", "b", "C"]
si desea que la primera aparición :
["a", "b", "A", "C"]\
.inject(Hash.new){ |h,element| h[element.downcase] = element unless h[element.downcase] ; h }\
.values
+1 Muy inteligente. – DanSingerman
un poco más eficiente y forma es hacer uso de las teclas uniq en hashes, así que mira esto:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] = j; hash}.values
devolverá el último elemento, en este caso
["A"]
mientras que usando || = operador como Asignar:
["a", "A"].inject(Hash.new){ |hash,j| hash[j.upcase] ||= j; hash}.values
volverá primer elemento, en este caso
["a"]
especialmente para matrices grandes esto debería ser más rápido que no buscamos en la matriz cada vez que se incluye ?
aplausos ...
Si está utilizando ActiveSupport, puede utilizar uniq_by. No afecta el caso de la salida final.
['A','a'].uniq_by(&:downcase) # => ['A']
Hay otra manera de hacerlo. En realidad, puede pasar un bloque a uniq
o uniq!
que se puede usar para evaluar cada elemento.
["A", "a"].uniq { |elem| elem.downcase } #=> ["A"]
o
["A", "a"].uniq { |elem| elem.upcase } #=> ["A"]
En este caso, sin embargo, todo estará entre mayúsculas y minúsculas por lo que siempre devolverá la matriz ["A"]
Gran respuesta. Tenga en cuenta que una variación ligeramente más corta es '[" A "," a "]. Uniq (&: downcase)'. – antinome
@antinome Mucho más legible. –
Esta debería ser claramente la respuesta aceptada ... –
Mientras que esto funcionaría para el ejemplo dado si la lista era algo así como ["Hola", "HOLA"] luego ["Hola", "HOLA"]. Map {| i | i.downcase} .uniq devolvería ["hello"] que no coincide con ninguna de las cadenas en la lista original. – mikej
La solución editada es válida, excepto que construirá la lista reducida usando result.map {| i | i.downcase} varias veces (una para cada elemento en la lista original) así que tal vez ejecute eso una vez como una declaración separada y almacene en una variable temporal si la lista es grande. – mikej
La solución de @Eric C es mucho más simple. – depquid