2015-10-22 12 views
9

Làm cách nào để sắp xếp danh sách các phiên bản trong Ruby? Tôi đã nhìn thấy những thứ về tự nhiên, nhưng đây là một bước xa hơn thế.Sắp xếp phiên bản (với alphas, betas, vv) trong ruby ​​

Input là một loạt các chuỗi như thế này:

input = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3'] 

Tôi gần như có thể làm điều đó với các naturally đá quý:

require 'naturally' 
Naturally.sort(input) 
=> ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b12", "10.0.0b3"]  

Vấn đề: 10.0.0b3 được sắp xếp sau khi 10.0.0b12; 10.0.0b3 phải là đầu tiên.

Có ai có cách hoạt động không? Các ngôn ngữ khác cũng hữu ích!

+1

Đó là chuỗi phiên bản không điển hình. Bạn không có khả năng tìm ra giải pháp không có giá; bạn nên viết của riêng bạn. – meagar

+0

Tôi đã thay đổi nó để sử dụng Phiên bản ngữ nghĩa. Đó là điển hình hơn. –

+0

@MusashiAharon Đây không phải là phiên bản ngữ nghĩa khá. Đối với điều đó, bạn muốn 'b12'' b3', vv được đặt trước bởi một' -'. – Ajedi32

Trả lời

19

tàu với lớp Gem Ruby, biết về các phiên bản:

ar = ['10.0.0b12', '10.0.0b3', '10.0.0a2', '9.0.10', '9.0.3'] 

p ar.sort_by { |v| Gem::Version.new(v) } 
# => ["9.0.3", "9.0.10", "10.0.0a2", "10.0.0b3", "10.0.0b12"] 
+2

Đẹp. Đối với những gì nó có giá trị - có vẻ như điều này xử lý "alpha" và "beta" theo thứ tự abc. Tức là, '['9.0.10rc2', '9.0.10', '9.0.10rc1', '9.0.10a', '9.0.10test']' sản lượng '[" 9.0.10a "," 9.0.10rc1 " , "9.0.10rc2", "9.0.10test", "9.0.10"] '. Nên là đủ, vì "alpha/beta/pre-release/rc/release" xảy ra theo thứ tự bảng chữ cái, nhưng có thể là kỳ quặc nếu dữ liệu của bạn lệch quá xa. – DreadPirateShawn

+0

khá thú vị cách hoạt động: https://github.com/rubygems/rubygems/blob/1aa8033952d4eda5ca131039822f9548166ab507/lib/rubygems/version.rb#L336-L361 – Anthony

1

Nếu bạn giải thích điều này như "sắp xếp theo từng phân khúc của các chữ số", sau đó bạn sau đây sẽ xử lý ví dụ đầu vào của bạn ở trên:

input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last) 
=> ["9_0", "9_1", "10_0b3", "10_0b12"] 

Đó là,

  • cho mỗi giá trị, ví dụ như 10_0b3
  • chia trên bất kỳ chiều dài của các ký tự không chữ số, ví dụ như ["10","0","3"]
  • cast mỗi đoạn chữ số để nguyên, ví dụ: [10,0,3]
  • zip với sự đóng góp ban đầu, lợi suất [[[10, 0, 12], "10_0b12"], [[10, 0, 3], "10_0b3"], [[9, 0], "9_0"], [[9, 1], "9_1"]]
  • sắp xếp, nhờ [10,0,3] < [10,0,12]
  • nhận được giá trị cuối cùng của mỗi yếu tố, đó là giá trị đầu vào gốc tương ứng với mỗi giá trị có thể phân loại xử lý

Bây giờ được cấp, đây vẫn là số phiên bản khá tùy chỉnh đơn giản như "9_0a" so với "9_0b" sẽ không được xử lý, cả hai sẽ xuất hiện [9,0] - vì vậy bạn có thể cần phải tinh chỉnh thêm, nhưng hy vọng điều này bắt đầu bạn xuống một con đường khả thi.

EDIT: Ví dụ đầu vào ở trên thay đổi, vì vậy tôi đã thay đổi regex để chắc chắn rằng các chữ số khớp là tham lam, và với điều đó nó vẫn giữ lên:

irb(main):018:0> input = ['10.0.0b12', '10.0.0b3', '9.0.10', '9.0.3'] 
=> ["10.0.0b12", "10.0.0b3", "9.0.10", "9.0.3"] 
irb(main):025:0> input.map{ |ver| ver.split(%r{[^\d]+}).map(&:to_i) }.zip(input).sort.map(&:last) 
=> ["9.0.3", "9.0.10", "10.0.0b3", "10.0.0b12"] 
+0

Điều này không giúp ích gì, nhưng betas không phải là hậu tố duy nhất có thể. Chúng tôi cũng có thể có các ký tự chữ cái như '10 .0.0a2 'hoặc phát hành các ứng cử viên như '10 .0.0rc1'. Nếu đây là những side-by-side với những người khác, phân loại phá vỡ. –

Các vấn đề liên quan