Câu hỏi Cách tốt nhất để cắt một chuỗi thành các đoạn của một chiều dài đã cho trong Ruby là gì?


Tôi đã tìm kiếm một cách thanh lịch và hiệu quả để chunk một chuỗi thành các chất nền của một chiều dài nhất định trong Ruby.

Cho đến nay, điều tốt nhất tôi có thể nghĩ ra là:

def chunk(string, size)
  (0..(string.length-1)/size).map{|i|string[i*size,size]}
end

>> chunk("abcdef",3)
=> ["abc", "def"]
>> chunk("abcde",3)
=> ["abc", "de"]
>> chunk("abc",3)
=> ["abc"]
>> chunk("ab",3)
=> ["ab"]
>> chunk("",3)
=> []

Bạn có thể muốn chunk("", n) trở về [""] thay vì []. Nếu vậy, chỉ cần thêm dòng này làm dòng đầu tiên của phương thức:

return [""] if string.empty?

Bạn có đề xuất giải pháp nào tốt hơn không?

Chỉnh sửa

Nhờ Jeremy Ruten cho giải pháp thanh lịch và hiệu quả này:

def chunk(string, size)
    string.scan(/.{1,#{size}}/)
end

76
2018-04-16 01:06


gốc




Các câu trả lời:


Sử dụng String#scan:

>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,3}/)
=> ["abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz"]

137
2018-04-16 01:26



Ok, bây giờ điều này là tuyệt vời! Tôi biết phải có một cách tốt hơn. Cảm ơn rất nhiều Jeremy Ruten. - MiniQuark
def chunk (chuỗi, kích thước); string.scan (/. {1, # {size}} /); kết thúc - MiniQuark
Wow, bây giờ tôi cảm thấy ngu ngốc. Tôi thậm chí không bao giờ bận tâm để kiểm tra cách quét làm việc. - Chuck
Hãy cẩn thận với giải pháp này; đây là một regexp, và /. bit của nó có nghĩa là nó sẽ bao gồm tất cả các ký tự EXCEPT newlines \n. Nếu bạn muốn bao gồm dòng mới, hãy sử dụng string.scan(/.{4}/m) - professormeowingtons
Thật là một giải pháp thông minh! Tôi yêu regexps nhưng tôi sẽ không có mặc dù sử dụng quantifier cho mục đích này. Cảm ơn bạn Jeremy Ruten - Cec


Dưới đây là một cách khác để thực hiện:

"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }

=> ["abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz"]


16
2018-02-04 20:04



Ngoài ra: "abcdefghijklmnopqrstuvwxyz".chars.each_slice(3).map(&:join) - Finbarr
Tôi thích cái này vì nó hoạt động trên các chuỗi có chứa dòng mới. - Steve Davis
Đây sẽ là giải pháp được chấp nhận. Sử dụng tính năng quét có thể thả mã thông báo cuối cùng nếu độ dài không khớp mẫu. - count0


Tôi nghĩ rằng đây là giải pháp hiệu quả nhất nếu bạn biết chuỗi của bạn là bội số của kích thước chunk

def chunk(string, size)
    (string.length / size).times.collect { |i| string[i * size, size] }
end

và cho các bộ phận

def parts(string, count)
    size = string.length / count
    count.times.collect { |i| string[i * size, size] }
end

2
2017-07-26 14:00



Chuỗi của bạn không phải là bội số của kích thước chunk nếu bạn thay thế string.length / size với (string.length + size - 1) / size - mẫu này là phổ biến trong mã C mà phải đối phó với cắt ngắn số nguyên. - nitrogen


test.split(/(...)/).reject {|v| v.empty?}

Việc từ chối là cần thiết vì nó bao gồm khoảng trắng giữa các bộ. Regex-fu của tôi không phải là khá lên để xem làm thế nào để sửa chữa quyền đó ra khỏi đầu của tôi.


1
2018-04-16 01:20



các aproach quét sẽ quên đi không phù hợp caracteres, tức là: nếu u thử với một chuỗi 10 chiều dài chuỗi trên 3 phần, bạn sẽ có 3 phần và 1 yếu tố sẽ được giảm xuống, aproach của bạn không làm điều đó, vì vậy tốt nhất của nó. - vinicius gati


Có một số hạn chế khác mà bạn có trong tâm trí? Nếu không, tôi sẽ bị cám dỗ khủng khiếp để làm điều gì đó đơn giản như

[0..10].each {
   str[(i*w),w]
}

0
2018-04-16 01:15



Tôi không thực sự có bất kỳ hạn chế nào, ngoài việc có một cái gì đó đơn giản, thanh lịch và hiệu quả. Tôi thích ý tưởng của bạn, nhưng bạn có thể dịch nó thành một phương pháp được không? [0..10] có lẽ sẽ trở nên phức tạp hơn một chút. - MiniQuark
Tôi cố định ví dụ của mình để sử dụng str [iw, w] thay vì str [iw ... (i + 1) * w]. Tx - MiniQuark
Điều này nên (1..10). Thu thập thay vì [0..10] .each. [1..10] là một mảng bao gồm một phần tử - một phạm vi. (1..10) là phạm vi của chính nó. Và + mỗi + trả về tập hợp gốc mà nó được gọi ([1..10] trong trường hợp này) thay vì các giá trị được trả về bởi khối. Chúng tôi muốn + bản đồ + tại đây. - Chuck