2009-12-23 33 views
6

Quiero ordenar una matriz por cadenas primero y luego números. ¿Cómo hago esto?Ordenar cadenas y números en Ruby

+1

Su pregunta no es realmente lo suficientemente específica. ¿Qué estás tratando de ordenar? Cadenas, o personajes? ¿Y quieres decir que siempre quieres letras para ordenar menos que los números? ¿Qué pasa si una cuerda tiene letras y números mezclados? ¿O prefiere el tipo lexicográfico en el que las letras se ordenan antes que los números? –

+0

¿Podría aclarar su pregunta? ¿Tal vez dar un ejemplo del orden de clasificación que desea? –

+0

¿Qué hay en la matriz? – klochner

Respuesta

15

Un truco general para resolver complicados tipo es utilizar #sort_by, con el bloque devuelve una matriz que tiene el orden de clasificación primaria y secundaria (y, si lo necesita, terciarios, etc.)

a = ['foo', 'bar', '1', '2', '10'] 
b = a.sort_by do |s| 
    if s =~ /^\d+$/ 
    [2, $&.to_i] 
    else 
    [1, s] 
    end 
end 
p b # => ["bar", "foo", "1", "2", "10"] 

Esto funciona debido a la forma en que Ruby define la comparación de matrices. La comparación se define mediante el método Array#<=>:

Las matrices se comparan de forma "por elementos"; el primer elemento de ary se compara con el primero de other_ary usando el operador < =>, luego cada uno de los segundos elementos, etc. ... Tan pronto como el resultado de tal comparación sea distinto de cero (es decir, los dos elementos correspondientes no son iguales)), ese resultado se devuelve para toda la comparación de la matriz.

+0

¿Cómo se maneja cuando hay un objeto 'Flotante'? Se está rompiendo, cuando la colección contiene 'Float's ... Básicamente estoy usando tu código, pero se está rompiendo para objetos' Float' .. –

17

Ordene una matriz de números mixtos y cadenas colocando los números primero, y en orden, seguidos por los segundos y en orden.

>> a = [1, 2, "b", "a"] 

>> a.partition{|x| x.is_a? String}.map(&:sort).flatten 
=> ["a", "b", 1, 2] 
+0

De inmediato, gracias por la respuesta, – s84

+0

Me gustaría ir a la cama. En realidad, la matriz solo tiene cadenas, pero las cadenas pueden comenzar con un "número" de una letra – s84

+5

Increíble uso del combo 'partition ... flatten'. – akuhn

2

Normalmente, la alfabetización se hace con números primero. Si desea alfabetizar algo donde las letras están alfabetizadas antes que los números, deberá modificar la función de comparación utilizada.

# I realize this function could be done with less if-then-else logic, 
# but I thought this would be clearer for teaching purposes. 
def String.mysort(other) 
    length = (self.length < other.length) ? self.length : other.length 
    0.upto(length-1) do |i| 
    # normally we would just return the result of self[i] <=> other[i]. But 
    # you need a custom sorting function. 
    if self[i] == other[i] 
     continue # characters the same, skip to next character. 
    else 
     if self[i] ~= /[0-9]/ 
     if other[i] ~= /[0-9]/ 
      return self[i] <=> other[i] # both numeric, sort normally. 
     else 
      return 1 # self is numeric, other is not, so self is sorted after. 
     end 
     elsif other[i] ~= /[0-9]/ 
     return -1 # self is not numeric, other is, so self is sorted before. 
     else 
     return self[i] <=> other[i] # both non-numeric, sort normally. 
     end 
    end 
    end 

    # if we got this far, the segments were identical. However, they may 
    # not be the same length. Short sorted before long. 
    return self.length <=> other.length 
end 

['0','b','1','a'].sort{|x,y| x.mysort(y) } # => ['a', 'b', '0', '1'] 
0

Si está tratando de clasificar casos y números mixtos, solo unas pocas personas en la tierra pueden hacerlo fuera de las aplicaciones propietarias. Es un secreto con un golpe de ventosa. Debe usar un qsort que simplifique la clasificación hasta que mezcle casos (letras mayúsculas y minúsculas). Entonces la universidad, los libros y el internet te dejan colgando. Este truco vale su peso en oro y es el anillo de programación de bronce por todas las razones.

Para ordenar números con palabras, debe convertir los números en cadenas. Debe presortar usando mayúsculas. Si tiene las palabras "Ant", "ant" y "anT" en menos, todas deberían señalar la palabra "ANT" a la lista de clasificación en mayúsculas. A continuación, creará una lista (matriz) de solo estas tres palabras ["Ant", "ant" y "anT"] y usará qsort como desempate para ordenarlas.

Luego los inserta en una matriz de clasificación final. Es bastante difícil por diseño. "A" es 65 en ascii y 'a' es 97 con muchos caracteres basura entre 'Z' y 'a'! No es un accidente! Es una conspiración que te digo!

Se puede crear una tabla de clasificación de los grupos más sensatamente los personajes como:

A, a, B, b, C, C, D, d, E, E, F, f, G, g, H, h, I, i, J, j, K, k, L, l, M, m, N, n, ... 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 ...

construyendo la tabla alrededor de este bloque comenzando con "" (espacio) ascii 32 hasta 128. es probable que desee reordenar los números en secuencia para la A 65 es para solo ejemplo.

Esto hace que sea más fácil, pero es probable que cause un golpe de rendimiento fuera de las macros de la mayoría de los lenguajes de programación. ¡Buena suerte!

1

Aquí hay respuestas algo verbosas. Divida la matriz en dos matrices secundarias: cadenas y números, ordénelos y concatúrelos.

array = [1, 'b', 'a', 'c', 'd', 2, 4, 3] 
strings = [] 
numbers = [] 
array.each do |element| 
    if element.is_a? String 
    strings << element 
    else 
    numbers << element 
    end 
end 
sorted_array = strings.sort + numbers.sort 
sorted_array # ['a', 'b', 'c', 'd', 1, 2, 3, 4] 
2
a = ['1', '10', '100', '2', '42', 'hello', 'x1', 'x20', 'x100', '42x', '42y', '10.1.2', '10.10.2', '10.8.2'] 
a.map {|i| i.gsub(/\d+/) {|s| "%08d" % s.to_i } }.zip(a).sort.map{|x,y| y} 
# => ["1", "2", "10", "10.1.2", "10.8.2", "10.10.2", "42", "42x", "42y", "100", "hello", "x1", "x20", "x100"] 
+1

a.sort_by {| i | i.gsub (/ \ d + /) {| s | "% 08d"% s.to_i}} – bluexuemei

+0

@bluexuemei ah, eso es bastante limpio. Guay – neoneye

Cuestiones relacionadas