Soru Bir string'i Ruby'de belirli bir uzunlukta parçalara ayırmanın en iyi yolu nedir?


Ruby'de verilen bir uzunluğun alt dizelerine bir dizgeyi yerleştirmek için zarif ve verimli bir yol arıyordum.

Şimdiye kadar, bulabildiğim en iyisi şuydu:

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)
=> []

İsteyebilirsin chunk("", n) geri vermek [""] yerine []. Öyleyse, bunu yöntemin ilk satırı olarak ekleyin:

return [""] if string.empty?

Daha iyi bir çözüm önerebilir misiniz?

Düzenle

Bu zarif ve verimli çözüm için Jeremy Ruten'e teşekkürler:

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

76
2018-04-16 01:06


Menşei




Cevaplar:


kullanım 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



Tamam, şimdi bu mükemmel! Daha iyi bir yol olması gerektiğini biliyordum. Çok teşekkürler Jeremy Ruten. - MiniQuark
def yığın (dize, boyut); string.scan (/ {1, # {boyutu}} /.); son - MiniQuark
Vay, şimdi aptalım. Taramanın nasıl çalıştığını kontrol etmekten asla rahatsız olmadım. - Chuck
Bu çözüme dikkat edin; Bu bir regexp ve /. Bunun bir kısmı, tüm satırları satırsonları HARİÇ olduğu anlamına gelir. \n. Yeni satırlar eklemek istiyorsanız, string.scan(/.{4}/m) - professormeowingtons
Ne kadar akıllı bir çözüm! Düzenli ifadeleri seviyorum ama bu amaçla niceleyiciyi kullanmam mümkün olmazdı. Teşekkür ederim Jeremy Ruten - Cec


İşte bunu yapmanın başka bir yolu:

"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



Alternatif: "abcdefghijklmnopqrstuvwxyz".chars.each_slice(3).map(&:join) - Finbarr
Bunu seviyorum çünkü yeni satırlar içeren dizelerde çalışıyor. - Steve Davis
Bu kabul edilen çözüm olmalı. Uzunluğun eşleşmemesi durumunda taramayı kullanmak son jetonu bırakabilir Desen. - count0


Eğer string'in bir yığın büyüklüğünün çok olduğunu biliyorsanız, bunun en verimli çözüm olduğunu düşünüyorum.

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

ve parçalar için

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

2
2017-07-26 14:00



Değiştirirseniz, dizginiz çok sayıda yığın boyutu olmak zorunda değildir. string.length / size ile (string.length + size - 1) / size - bu model, tamsayı kesme işlemiyle uğraşmak zorunda olan C kodunda yaygındır. - nitrogen


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

Reddetme, aksi takdirde kümeler arasındaki boş alanı içerdiğinden gereklidir. Regex-fu'm kafamın üstünden nasıl düzeltileceğini görmezden gelmiyor.


1
2018-04-16 01:20



tarama yaklaşımı, eşleşmemiş caracteres'i unutacaktır, yani: eğer 3 parça üzerinde 10 uzunluğunda bir dize dilimi ile deneyiniz, 3 parçanız olacak ve 1 elemanın düşürüleceği, sizin yaklaşımınız bunu yapmıyor, bu yüzden en iyisi. - vinicius gati


Aklında olan başka bazı kısıtlamalar var mı? Aksi takdirde basit gibi bir şey yapmak için çok cazip olurdu

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

0
2018-04-16 01:15



Basit, zarif ve verimli bir şey olmanın ötesinde, hiç bir kısıtım yok. Fikrini beğendim, ama bunu bir yönteme çevirebilir misin lütfen? [0..10] muhtemelen biraz daha karmaşık hale gelirdi. - MiniQuark
Örneğimi str [i kullanmak için sabitledimw, w] yerine str [iw ..., (i + 1) *] w. Tx - MiniQuark
Bu, (0.,10) .each yerine (1..10) .collect olmalıdır. [1.10] bir elemandan oluşan bir dizidir - bir aralıktır. (1..10) aralığın kendisi. Ve + her +, bloğun döndürdüğü değerlerden ziyade çağrılan özgün koleksiyonu (bu durumda [1.10]) döndürür. + Harita + istiyoruz. - Chuck