2016-01-15 22 views
9

Próbuję posortować tablicę z mieszanką wartości int i string. Weźmy na przykład:Jak sortować tablicę int i stringów?

a = ["a", "b", 5, "c", 4, "d", "a1", "a12", 3, 13, 2, "13a", "12a"] 

Próbowałem:

a.sort do |x, y| 
    if x.class == y.class 
    x <=> y 
    else 
    x.class.to_s <=> y.class.to_s 
    end 
end 

Które zwraca:

[2, 3, 4, 5, 13, "12a", "13a", "a", "a1", "a12", "b", "c", "d"] 

Wynikiem czego chcę to:

[2, 3, 4, 5, "12a", 13, "13a", "a", "a1", "a12", "b", "c", "d"] 
+0

Czy w łańcuchach może znajdować się więcej niż jedna liczba, np. "" a1b2c3 "'? – Stefan

+0

Co jest poprawne? '[" a1 "," a12 "," a2 "]' lub '[" a1 "," a2 "," a12 "]'? – Stefan

+0

@Stefan Możliwe, że w ciągu znaków znajduje się więcej niż jedna cyfra. Te ostatnie '[" a1 "," a2 "," a12 "]' –

Odpowiedz

11
a.sort_by { |x| [(x.to_s.match(/^\d+/) ? x.to_i : 1.0/0), x.to_s] } 

Chodzi o to, aby najpierw sortować według wartości liczbowej, a następnie według wartości ciągu. Jeśli ciąg nie zaczyna się od wartości numerycznej, należy z całą mocą uznać wartość numeryczną za nieskończoność.


EDIT: Jak PO wyjaśnił, że chce, aby brać pod uwagę nie tylko wiodącą wartość liczbową, ale wszystkie, które następują, możemy wykorzystać ten sam pomysł, tylko tym razem musimy zastosować go na każdej jednostce numeryczna i nieliczbowa jednostka w łańcuchu:

a.sort_by do |x| 
    x.to_s.split(/(\D+)/).map do |y| 
    [(y.match(/\d/) ? y.to_i : 1.0/0), y] 
    end 
end 
+1

'0' w tablicy kończyłoby się pomiędzy' '13a" 'a' "a" ' – Stefan

+0

@Stefan, zaktualizowano. – ndn

+0

To lepiej, ale nie sortuje '[" a13 "," a2 "]' prawidłowo. – Stefan