রুবিতে একটি নির্দিষ্ট দৈর্ঘ্যের খণ্ডগুলিতে স্ট্রিং কাটানোর সর্বোত্তম উপায় কী?


89

আমি রুবিতে একটি নির্দিষ্ট দৈর্ঘ্যের সাবস্ট্রিংগুলিতে একটি স্ট্রিং ছড়িয়ে দেওয়ার জন্য একটি মার্জিত এবং দক্ষ উপায় খুঁজছি।

এখনও অবধি, আমি যে সেরাটির সাথে আসতে পারলাম তা হ'ল:

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

আপনি পরিবর্তে chunk("", n)ফিরে আসতে চাইতে পারেন । যদি তা হয় তবে কেবল পদ্ধতির প্রথম লাইন হিসাবে এটি যুক্ত করুন:[""][]

return [""] if string.empty?

আপনি কি আরও ভাল সমাধান সুপারিশ করতে পারেন?

সম্পাদনা করুন

এই মার্জিত এবং দক্ষ সমাধানের জন্য জেরেমি রুটেনকে ধন্যবাদ: [সম্পাদনা করুন: দক্ষ নয়!]

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

সম্পাদনা করুন

আসল স্লাইস-ভিত্তিক সমাধানের তুলনায় স্ট্রিং.স্কান দ্রবণটি 512 কে 1 কে টুকরোতে 10000 বার কাটাতে প্রায় 60 সেকেন্ড সময় নেয় যা কেবল 2.4 সেকেন্ড লাগে takes


আপনার আসল সমাধানটি যতটা সম্ভব দক্ষ এবং মার্জিত সম্পর্কে: স্ট্রিংয়ের প্রতিটি চরিত্রটি কোথায় কাটা উচিত তা জানার দরকার নেই বা পুরো জিনিসটিকে অ্যারেতে পরিণত করার দরকার নেই এবং তারপরে আবার ফিরে আসতে হবে।
android.weasel

উত্তর:


159

ব্যবহার 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"]

ঠিক আছে, এখন এটি দুর্দান্ত! আমি জানতাম সেখানে আরও ভাল উপায় থাকতে হবে। অনেক অনেক ধন্যবাদ জেরেমি রুটেন।
MiniQuark

4
ডিফ অংশ (স্ট্রিং, আকার); স্ট্রিং.স্কান (/। {1, # {আকার}} /); শেষ
MiniQuark

4
বাহ, আমি এখন বোকা বোধ করছি। এমনকি স্ক্যান কীভাবে কাজ করে তা পরীক্ষা করার জন্য আমি কখনও মাথা ঘামাইনি।
চক

18
এই সমাধানটি সম্পর্কে সতর্কতা অবলম্বন করুন; এটি একটি রেজিপ্সপ, এবং এর বিটটির /.অর্থ এটিতে সমস্ত অক্ষর এক্সক্লুটি নিউলাইন অন্তর্ভুক্ত থাকবে \n। আপনি নতুন লাইন, ব্যবহার অন্তর্ভুক্ত করতে চাইলেstring.scan(/.{4}/m)
professormeowingtons

4
কী চতুর সমাধান! আমি regexps পছন্দ করি কিন্তু আমি এই উদ্দেশ্যে কোয়ান্টিফায়ার ব্যবহার করে না। ধন্যবাদ জেরেমি রুটেন
সিইসি

18

এটি করার আরেকটি উপায় এখানে:

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

=> ["এবিসি", "ডিএফ", "জিআই", "জে কে এল", "এমএনও", "পিকিআর", "স্টু", "ভিডব্লিউ", "ইজেড"]


16
বিকল্পভাবে:"abcdefghijklmnopqrstuvwxyz".chars.each_slice(3).map(&:join)
ফিনব্বর

4
আমি এটি পছন্দ করি কারণ এটি নতুন পংক্তিত স্ট্রিংগুলিতে কাজ করে।
স্টিভ ডেভিস

4
এটি গ্রহণযোগ্য সমাধান হওয়া উচিত। দৈর্ঘ্যের প্যাটার্নের সাথে মেলে নালে স্ক্যান ব্যবহার করা শেষ টোকন ফেলে দিতে পারে ।
গণনা 0

6

আমি মনে করি এটি যদি আপনি জানেন যে আপনার স্ট্রিংটি খণ্ড আকারের একাধিক efficient

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

এবং অংশ জন্য

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

4
যদি আপনি এর সাথে প্রতিস্থাপন string.length / sizeকরেন তবে আপনার স্ট্রিংয়ের পরিমাণগুলি একাধিক হতে হবে না (string.length + size - 1) / size- এই প্যাটার্নটি সি কোডে প্রচলিত যা পুরোপুরি কাটা কাটা করতে হবে।
নাইট্রোজেন

3

বড় স্ট্রিং প্রক্রিয়াকরণ করার সময় কিছুটা আলাদা কেসের জন্য এখানে আরও একটি সমাধান রয়েছে এবং একসাথে সমস্ত খণ্ডগুলি সংরক্ষণ করার দরকার নেই। এইভাবে এটি এককালে একক অংশ সংরক্ষণ করে এবং কাটা স্ট্রিংয়ের চেয়ে অনেক দ্রুত সম্পাদন করে:

io = StringIO.new(string)
until io.eof?
  chunk = io.read(chunk_size)
  do_something(chunk)
end

খুব বড় স্ট্রিং জন্য, এই হল দ্বারা পর্যন্ত এটা করতে সবচেয়ে ভালো উপায় । এই মেমরিতে সমগ্র স্ট্রিং পড়া ও পেয়ে এড়াতে হবে Errno::EINVALমত ত্রুটি Invalid argument @ io_freadএবং Invalid argument @ io_write
জোশুয়া পিন্টার

2

আমি একটি ছোট পরীক্ষা করেছি যা প্রায় 593MB ডেটা 18991 32KB টুকরো টুকরো করে। আপনার স্লাইস + মানচিত্রের সংস্করণটি আমি সিটিআরএল + সি চাপার আগে কমপক্ষে 15 মিনিটের জন্য 100% সিপিইউ ব্যবহার করে চালিয়েছি। স্ট্রিং # আনপ্যাকটি ব্যবহার করে এই সংস্করণটি 3.6 সেকেন্ডের মধ্যে শেষ হয়েছে:

def chunk(string, size)
  string.unpack("a#{size}" * (string.size/size.to_f).ceil)
end

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

প্রত্যাখ্যান করা প্রয়োজনীয় কারণ এটিতে অন্যথায় সেটগুলির মধ্যে ফাঁকা স্থান রয়েছে। আমার রেজেক্স-ফু কেবল আমার মাথার উপরের অংশ থেকে কীভাবে এটি ঠিক করতে হবে তা দেখার পক্ষে যথেষ্ট নয়।


স্ক্যান এপ্রোচটি ম্যাচহীন ক্যারাকটিয়ারগুলি সম্পর্কে ভুলে যাবে, যেমন: আপনি যদি 3 টি অংশে 10 দৈর্ঘ্যের স্ট্রিং স্লাইস দিয়ে চেষ্টা করেন তবে আপনার 3 অংশ থাকবে এবং 1 টি উপাদান বাদ যাবে, আপনার এপ্রোচ তা করবেন না, তাই এটি সেরা best
ভিনিসিয়াস গাতি

1

স্ট্রিংয়ের শেষ অংশটি খণ্ড আকারের চেয়ে কম হতে পারে এমন একটি ভাল সমাধান বিবেচনা করে:

def chunk(inStr, sz)  
  return [inStr] if inStr.length < sz  
  m = inStr.length % sz # this is the last part of the string
  partial = (inStr.length / sz).times.collect { |i| inStr[i * sz, sz] }
  partial << inStr[-m..-1] if (m % sz != 0) # add the last part 
  partial
end

0

আপনার মনে আছে এমন আরও কিছু প্রতিবন্ধকতা রয়েছে? অন্যথায় আমি খুব সাধারণভাবে কিছু করার প্রলুব্ধ হব

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

সরল, মার্জিত এবং দক্ষ কিছু না করে আমার আসলেই কোনও প্রতিবন্ধকতা নেই। আমি আপনার ধারণাটি পছন্দ করি তবে আপনি কি কোনও পদ্ধতিতে এটি অনুবাদ করতে আপত্তি করবেন? [0..10] সম্ভবত কিছুটা জটিল হয়ে উঠবে।
MiniQuark

আমি আমার উদাহরণটি স্থির করেছি str [i w, w] এর পরিবর্তে আরআর [আমি ডাব্লু ... Tx
MiniQuark

এটি হওয়া উচিত (১.১.১০)। [0..10] এর পরিবর্তে নির্বাচন করুন ea [1..10] হ'ল একটি অ্যারে যা একটি উপাদান - একটি ব্যাপ্তি নিয়ে গঠিত। (1..10) নিজেই পরিসীমা। এবং + প্রতিটি + ব্লক দ্বারা ফিরে আসা মানগুলির পরিবর্তে ([1..10]) এটি কল করা মূল সংগ্রহটি ফিরিয়ে দেয়। আমরা এখানে + মানচিত্র + চাই।
চক

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.