পাইথনের স্ট্রিং সংমিশ্রিত করার জন্য পছন্দের উপায় কোনটি?


358

পাইথনের যেহেতু stringপরিবর্তন করা যায় না, তাই আমি ভাবছিলাম কীভাবে আরও দক্ষতার সাথে স্ট্রিং যুক্ত করতে পারি?

আমি এটি লিখতে পারেন:

s += stringfromelsewhere

বা এই মত:

s = []
s.append(somestring)

later

s = ''.join(s)

এই প্রশ্নটি লেখার সময়, আমি বিষয়টির সাথে কথা বলার একটি ভাল নিবন্ধ পেয়েছি।

http://www.skymind.com/~ocrow/python_string/

তবে এটি পাইথন ২.x এ রয়েছে, সুতরাং প্রশ্নটি কি পাইথন ৩-তে কিছু পরিবর্তন হবে?


উত্তর:


433

সেরা একটি স্ট্রিং পরিবর্তনশীল করার জন্য একটি স্ট্রিং সংযোজন প্রণালী ব্যবহার করা +বা +=। এটি কারণ এটি পাঠযোগ্য এবং দ্রুত। এগুলিও ঠিক তত দ্রুত, আপনি যেটি পছন্দ করেন তা স্বাদের বিষয়, পরেরটি সর্বাধিক সাধারণ। এখানে timeitমডিউলটির সময় রয়েছে :

a = a + b:
0.11338996887207031
a += b:
0.11040496826171875

যাইহোক, যারা তালিকাগুলি রাখার এবং সেগুলিতে সংযোজন এবং তারপরে সেই তালিকায় যোগদানের পরামর্শ দেন, কারণ একটি তালিকায় একটি স্ট্রিং যুক্ত করা সম্ভবত স্ট্রিং বাড়ানোর তুলনায় খুব দ্রুত is এবং এটি সত্য হতে পারে, কিছু ক্ষেত্রে। এখানে উদাহরণস্বরূপ, এক-বর্ণের স্ট্রিংয়ের এক মিলিয়ন সংযোজন, প্রথমে একটি স্ট্রিংয়ে, এবং পরে তালিকাতে:

a += b:
0.10780501365661621
a.append(b):
0.1123361587524414

ঠিক আছে, দেখা যাচ্ছে যে ফলস্বরূপ স্ট্রিং যখন মিলিয়ন অক্ষর দীর্ঘ হয় তখনও সংযোজনটি আরও দ্রুত ছিল।

এবার এক হাজার চরিত্রের দীর্ঘ স্ট্রিংকে এক হাজার বার যুক্ত করার চেষ্টা করি:

a += b:
0.41823482513427734
a.append(b):
0.010656118392944336

শেষ স্ট্রিংটি প্রায় 100MB লম্বা হয়ে যায়। এটি বেশ ধীর ছিল, একটি তালিকায় যুক্ত হওয়া আরও দ্রুত ছিল। যে সময় চূড়ান্ত অন্তর্ভুক্ত না a.join()। তাহলে আর কতক্ষণ লাগবে?

a.join(a):
0.43739795684814453

Oups। এমনকি এই ক্ষেত্রে সক্রিয় হয়, সংযোজন / যোগদান ধীর হয়।

সুতরাং এই সুপারিশ কোথা থেকে আসে? পাইথন 2?

a += b:
0.165287017822
a.append(b):
0.0132720470428
a.join(a):
0.114929914474

ঠিক আছে, আপনি যদি খুব দীর্ঘ স্ট্রিং ব্যবহার করেন (তবে আপনি সাধারণত নন, মেমরির 100MB এর স্ট্রিংটি কী থাকে?) সেখানে সংযোজন / যুক্ত হওয়া প্রান্তিকভাবে দ্রুত হয়

তবে আসল ক্লিঞ্জারটি পাইথন ২.৩ 3 যেখানে আমি আপনাকে সময়গুলিও দেখাব না, কারণ এটি এত ধীর যে এখনও শেষ হয়নি। এই পরীক্ষাগুলি হঠাৎ কয়েক মিনিট সময় নেয় । সংযোজন / যোগদান ব্যতীত যা পরবর্তী পাইথনের অধীনে তত দ্রুত।

হা. পাথরের যুগে পাইথনের পিছনে স্ট্রিং কনটেনটেশন খুব ধীর ছিল। তবে ২.৪-তে এটি (বা কমপক্ষে পাইথন ২.৪..7) নয়, সুতরাং পাইথন ২.৩ আপডেট হওয়া বন্ধ হওয়ার পরে ২০০৮ সালে অ্যাপেন্ড / যোগ দেওয়ার পরামর্শটি পুরানো হয়ে যায় এবং আপনার এটি ব্যবহার বন্ধ করে দেওয়া উচিত ছিল। :-)

(আপডেট: যখন আমি আরো সাবধানে যে ব্যবহার পরীক্ষা হয়নি দেখা যাচ্ছে +এবং +=পাইথন 2.3 তে দ্রুততর দুটি স্ট্রিং জন্য ভাল হিসাবে ব্যবহারের সুপারিশ। ''.join()একটি ভুল বোঝাবুঝি হতে হবে)

তবে এটি সিপিথন। অন্যান্য বাস্তবায়নে অন্যান্য উদ্বেগ থাকতে পারে। এবং এটি হ'ল অপর কারণ কেন অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল। আপনি যদি প্রথমটি পরিমাপ না করেন তবে "দ্রুত" বলে মনে করা এমন কোনও প্রযুক্তি ব্যবহার করবেন না।

সুতরাং স্ট্রিং কনটেনটেশন করার জন্য "সেরা" সংস্করণটি হল + বা + = ব্যবহার করা । এবং যদি এটি আপনার পক্ষে ধীর হয়ে যায়, যা প্রায় অসম্ভব, তবে অন্য কিছু করুন।

তাহলে আমি কেন আমার কোডটিতে প্রচুর পরিমাণে সংযোজন / যোগদান করব? কারণ মাঝে মাঝে এটি আসলে পরিষ্কার হয়। বিশেষত যখন যা কিছু আপনার একসাথে করা উচিত তা স্পেস বা কমা বা নিউলাইন দ্বারা আলাদা করা উচিত।


10
আপনার যদি একাধিক স্ট্রিং থাকে (n> 10) ""। জয়েন্ট (list_of_strings) এখনও দ্রুত
মিক্কো ওহতামায়

11
+ = দ্রুত হওয়ার কারণটি হ'ল, সিপাইথনে পারফরম্যান্স হ্যাক রয়েছে যদি রেফকাউন্টটি 1 হয় - এটি অন্যান্য সমস্ত অজগর বাস্তবায়নের চেয়ে পৃথক হয়ে যায় (একটি বিশেষ কনফিগার করা পাইপি বিল্ড ব্যতীত)
রনি

17
কেন এতো উপকার করা হচ্ছে? চতুর্ভুজ সময় অ্যালগরিদম ঠিক করার জন্য একটি ভঙ্গুর হ্যাকের মূলত পরিমাণটি কী এমন একটি অ্যালগরিদম ব্যবহার করা কীভাবে ভাল? এছাড়াও আপনি "অকালীন অপটিমাইজেশন সমস্ত মন্দের মূল" এর বিন্দুটি পুরোপুরি ভুল বুঝেন। উক্তিটি ছোট অপ্টিমাইজেশনের কথা বলছে। এটি ও (এন ^ 2) থেকে ও (এন) এ যাচ্ছে যা কোনও ছোট্ট অপ্টিমাইজেশন নয়।
ওয়েজ

12
এখানে প্রকৃত উদ্ধৃতিটি দেওয়া আছে: "আমাদের ছোট কার্যকারিতা সম্পর্কে ভুলে যাওয়া উচিত, সময়ের প্রায় 97% বলুন: অকালীন অনুকূলতা সমস্ত মন্দের মূল Yet তবুও আমাদের এই সমালোচনামূলক 3% তে আমাদের সুযোগগুলি অতিক্রম করা উচিত নয় A একটি ভাল প্রোগ্রামার না এ জাতীয় যুক্তি দিয়ে আত্মতৃপ্তিতে জড়িয়ে পড়ুন, তিনি সমালোচনামূলক কোডটি মনোযোগ সহকারে দেখলে বুদ্ধিমান হন; তবে কেবল সেই কোডটি চিহ্নিত হওয়ার পরে "
ওয়েজ

2
কেউ বলছেন না যে a + b ধীর। আপনি যখন একাধিকবার = a + b করছেন তখন এটি চতুর্ভুজ হয়। a + b + c ধীরে ধীরে নয়, আমি ধীরগতিতে পুনরাবৃত্তি করব না কারণ এটি কেবল প্রতিটি স্ট্রিং একবারই অতিক্রম করতে হবে, যেখানে এটি a = a + b পদ্ধতির সাথে পূর্ববর্তী স্ট্রিংগুলিকে অনেকবার পুনঃপ্রক্রিয়া করতে হবে (ধরে নিচ্ছেন যে এটি লুপে রয়েছে) কিছু প্রকারের)। মনে রাখবেন স্ট্রিং অপরিবর্তনীয়।
ওয়েজ

52

আপনি যদি অনেকগুলি মানকে সম্মতি দিচ্ছেন তবে তাও নয়। তালিকা যুক্ত করা ব্যয়বহুল। আপনি তার জন্য স্ট্রিংআইও ব্যবহার করতে পারেন। বিশেষত যদি আপনি এটিকে অনেকগুলি ক্রিয়াকলাপ তৈরি করে চলেছেন।

from cStringIO import StringIO
# python3:  from io import StringIO

buf = StringIO()

buf.write('foo')
buf.write('foo')
buf.write('foo')

buf.getvalue()
# 'foofoofoo'

আপনার যদি ইতিমধ্যে অন্য কোনও ক্রিয়াকলাপ থেকে আপনার কাছে একটি সম্পূর্ণ তালিকা ফিরে আসে, তবে কেবলমাত্র এটি ব্যবহার করুন ''.join(aList)

পাইথন এফএকিউ: একসাথে অনেকগুলি স্ট্রিং সংলগ্ন করার সবচেয়ে কার্যকরী উপায় কী?

স্ট্র এবং বাইট অবজেক্টগুলি অপরিবর্তনীয়, তাই প্রতিটি স্ট্রাক্টেশন একটি নতুন অবজেক্ট তৈরি করার কারণে অনেকগুলি স্ট্রিংকে একসাথে যুক্ত করা অকার্যকর। সাধারণ ক্ষেত্রে, মোট রানটাইম ব্যয় মোট স্ট্রিং দৈর্ঘ্যের চতুর্ভুজ।

অনেকগুলি স্ট্রিং অবজেক্ট জমা করতে, প্রস্তাবিত প্রতিমাটি হ'ল তাদের একটি তালিকাতে রাখুন এবং শেষে str.join () কল করুন:

chunks = []
for s in my_strings:
    chunks.append(s)
result = ''.join(chunks)

(আর একটি যুক্তিযুক্ত দক্ষ আইডিয়ম io.StringIO ব্যবহার করা হয়)

অনেকগুলি বাইট অবজেক্ট জমা করতে, প্রস্তাবিত প্রতিমাটি হ'ল ইন-প্লেস কনটেনটেশন (+ = অপারেটর) ব্যবহার করে বাইটেরে অবজেক্টটি বাড়ানো:

result = bytearray()
for b in my_bytes_objects:
    result += b

সম্পাদনা: আমি নির্বোধ ছিলাম এবং ফলাফলগুলি পেছনের দিকে আটকে দিয়েছিলাম, এটিকে দেখে মনে হচ্ছে যে তালিকাতে যুক্ত করা সিস্ট্রিংআইওর চেয়ে দ্রুত ছিল। আমি বাইটেরে / স্ট্র কন্টেটের জন্য পরীক্ষাগুলিও যুক্ত করেছি, পাশাপাশি বড় স্ট্রিং সহ বৃহত্তর তালিকা ব্যবহার করে দ্বিতীয় দফার পরীক্ষাগুলিও যুক্ত করেছি। (অজগর ২.7.৩)

আইপিথন পরীক্ষার উদাহরণ স্ট্রিংয়ের বৃহত তালিকার জন্য

try:
    from cStringIO import StringIO
except:
    from io import StringIO

source = ['foo']*1000

%%timeit buf = StringIO()
for i in source:
    buf.write(i)
final = buf.getvalue()
# 1000 loops, best of 3: 1.27 ms per loop

%%timeit out = []
for i in source:
    out.append(i)
final = ''.join(out)
# 1000 loops, best of 3: 9.89 ms per loop

%%timeit out = bytearray()
for i in source:
    out += i
# 10000 loops, best of 3: 98.5 µs per loop

%%timeit out = ""
for i in source:
    out += i
# 10000 loops, best of 3: 161 µs per loop

## Repeat the tests with a larger list, containing
## strings that are bigger than the small string caching 
## done by the Python
source = ['foo']*1000

# cStringIO
# 10 loops, best of 3: 19.2 ms per loop

# list append and join
# 100 loops, best of 3: 144 ms per loop

# bytearray() +=
# 100 loops, best of 3: 3.8 ms per loop

# str() +=
# 100 loops, best of 3: 5.11 ms per loop

2
cStringIOপাই 3 তে নেই doesn't io.StringIOপরিবর্তে ব্যবহার করুন।
lvc

2
কেন বার বার স্ট্রিং এ যুক্ত করা ব্যয়বহুল হতে পারে: joelonsoftware.com/articles/fog0000000319.html
ওয়েজ


8

প্রস্তাবিত পদ্ধতিটি এখনও সংযোজন এবং যোগদানের জন্য রয়েছে।


1
আপনি আমার উত্তর থেকে দেখতে পাচ্ছেন, এটি নির্ভর করে আপনি কতটি স্ট্রিংকে সংঘবদ্ধ করছেন। আমি এ সম্পর্কে কিছু সময় নিয়েছি (আমার উত্তর সম্পর্কে আমার মন্তব্যে আমি যে কথার সাথে যুক্ত ছিলাম তা দেখুন) এবং সাধারণত এটি দশজনের বেশি না হলে + ব্যবহার করুন।
লেনার্ট রেজেব্রো

1
পিইপি 8 এতে উল্লেখ করেছে ( পাইথন.আর / দেবদেবী / পেপস / পেপ-0008 / # প্রোগ্রাম / বার্ষিক প্রস্তাবনা )। যুক্তিটি হ'ল সিপিথনের স্ট্রিং কনটেনটেশনের জন্য + = দিয়ে বিশেষ অপ্টিমাইজেশন রয়েছে, অন্য প্রয়োগগুলি নাও পারে।
কোয়ান্টাম

8

আপনি যে স্ট্রিংগুলি সংঘবদ্ধ করছেন তা যদি আক্ষরিক হয় তবে স্ট্রিংকে আক্ষরিক সংক্ষিপ্তকরণ ব্যবহার করুন

re.compile(
        "[A-Za-z_]"       # letter or underscore
        "[A-Za-z0-9_]*"   # letter, digit or underscore
    )

আপনি যদি কোনও স্ট্রিংয়ের অংশের উপরে (উপরে হিসাবে) মন্তব্য করতে চান বা আপনি যদি আক্ষরিক অংশের জন্য কাঁচা স্ট্রিং বা ট্রিপল কোট ব্যবহার করতে চান তবে এটি সমস্ত ক্ষেত্রে কার্যকর।

যেহেতু সিনট্যাক্স স্তরে এটি ঘটে এটি শূন্য কনটেনটেশন অপারেটর ব্যবহার করে।


7

আপনি এই ফাংশন লিখুন

def str_join(*args):
    return ''.join(map(str, args))

তারপরে আপনি যেখানে খুশি কল করতে পারবেন

str_join('Pine')  # Returns : Pine
str_join('Pine', 'apple')  # Returns : Pineapple
str_join('Pine', 'apple', 3)  # Returns : Pineapple3

1
str_join = lambda *str_list: ''.join(s for s in str_list)
রিক ২:0

6

কিছুটা তারিখের সময় কোডটি লাইক অফ পাইথুনিস্টা: আইডিয়োম্যাটিক পাইথন এই বিভাগে সুপারিশ join()করেছে । পাইথনস্পিডের পারফরম্যান্স টিপস এর বিভাগে স্ট্রিং কনটেনটেশনের উপর যেমনটি নিম্নলিখিত দাবি অস্বীকার করে:+

পাইথনের পরবর্তী সংস্করণগুলির সাথে এই বিভাগটির যথার্থতা বিতর্কিত। সিপিথন ২.২-এ স্ট্রিং কনকেন্টেশন মোটামুটি দ্রুত, যদিও এটি অন্যান্য পাইথন বাস্তবায়নের ক্ষেত্রেও একইভাবে প্রযোজ্য না। আলোচনার জন্য কনক্যাটেনটেশন টেস্টকোড দেখুন।


6

'+' দ্বারা পংক্তির স্ট্রিং কনকেন্টেশন ব্যবহার করা স্থিতিশীলতা এবং ক্রস বাস্তবায়নের ক্ষেত্রে কনক্যাটেনেশনের বৃহত্তম পদ্ধতি কারণ এটি সমস্ত মান সমর্থন করে না। পিইপি 8 স্ট্যান্ডার্ড এটিকে নিরুৎসাহিত করে এবং দীর্ঘমেয়াদী ব্যবহারের জন্য বিন্যাস (), যোগদান () এবং অ্যাপেন্ড () যোগ করতে উত্সাহ দেয়।

লিঙ্কযুক্ত "প্রোগ্রামিং সুপারিশ" বিভাগ থেকে উদ্ধৃত হিসাবে:

উদাহরণস্বরূপ, সিপিথনের কার্যনির্বাহী স্ট্রিং কনটেনটেশনের কার্যকর প্রয়োগের উপর নির্ভর করতে হবে না a + = b বা a = a + b আকারে statements এই অপ্টিমাইজেশনটি সিপিথনেও নাজুক (এটি কেবল কিছু ধরণের জন্য কাজ করে) এবং বাস্তবায়নগুলিতে একেবারেই উপস্থিত হয় না যা পুনরায় গণনা ব্যবহার করে না। গ্রন্থাগারের কর্মক্ষমতা সংবেদনশীল অংশগুলিতে পরিবর্তে '' .জয়াইন () ফর্মটি ব্যবহার করা উচিত। এটি নিশ্চিত করবে যে বিভিন্ন বাস্তবায়ন জুড়ে রৈখিক সময়ে সংমিশ্রণ ঘটে।


5
রেফারেন্স লিঙ্কটি চমৎকার হত :)

5

@ জেডি যেমন পাইথনের ডকুমেন্টেশন ব্যবহার করার জন্য str.joinবা io.StringIOস্ট্রিং কন্টেটিংয়ের পরামর্শ দেয় । এবং বলে যে +=পাইথন ২.৪ থেকে একটি অপ্টিমাইজেশন থাকা সত্ত্বেও কোনও বিকাশকারীকে একটি লুপ থেকে চতুর্ভুজ সময় আশা করা উচিত । যেমন এই উত্তর বলে:

পাইথন যদি সনাক্ত করে যে বাম আর্গুমেন্টের অন্য কোনও রেফারেন্স নেই, তবে এটি reallocস্ট্রিংটির স্থানে আকার পরিবর্তন করে একটি অনুলিপিটি এড়ানোর চেষ্টা করার আহ্বান জানায় । এটি এমন কোনও বিষয় নয় যা আপনার কখনও নির্ভর করা উচিত, কারণ এটি একটি বাস্তবায়ন বিশদ এবং কারণ যদি reallocপ্রায়শই স্ট্রিংটি সরিয়ে নেওয়া প্রয়োজন হয়, পারফরম্যান্স যাইহোক O (n ^ 2) এ অবনমিত হয়।

আমি রিয়েল-ওয়ার্ল্ড কোডের একটি উদাহরণ দেখাব যা +=এই অপ্টিমাইজেশানের উপর নির্লজ্জভাবে নির্ভর করেছিল , তবে এটি প্রয়োগ হয়নি। নীচের কোডটি সংক্ষিপ্ত স্ট্রিংগুলির একটি পুনরাবৃত্তকারীকে একটি বৃহত এপিআইতে ব্যবহারের জন্য বড় অংশগুলিতে রূপান্তর করে।

def test_concat_chunk(seq, split_by):
    result = ['']
    for item in seq:
        if len(result[-1]) + len(item) > split_by: 
            result.append('')
        result[-1] += item
    return result

এই কোডটি চতুর্ভুজ সময় জটিলতার কারণে ঘন্টার জন্য সাহিত্য চলতে পারে। নীচে প্রস্তাবিত ডেটা স্ট্রাকচার সহ বিকল্পগুলি রয়েছে:

import io

def test_stringio_chunk(seq, split_by):
    def chunk():
        buf = io.StringIO()
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                size += buf.write(item)
            else:
                yield buf.getvalue()
                buf = io.StringIO()
                size = buf.write(item)
        if size:
            yield buf.getvalue()

    return list(chunk())

def test_join_chunk(seq, split_by):
    def chunk():
        buf = []
        size = 0
        for item in seq:
            if size + len(item) <= split_by:
                buf.append(item)
                size += len(item)
            else:
                yield ''.join(buf)                
                buf.clear()
                buf.append(item)
                size = len(item)
        if size:
            yield ''.join(buf)

    return list(chunk())

এবং একটি মাইক্রো-বেঞ্চমার্ক:

import timeit
import random
import string
import matplotlib.pyplot as plt

line = ''.join(random.choices(
    string.ascii_uppercase + string.digits, k=512)) + '\n'
x = []
y_concat = []
y_stringio = []
y_join = []
n = 5
for i in range(1, 11):
    x.append(i)
    seq = [line] * (20 * 2 ** 20 // len(line))
    chunk_size = i * 2 ** 20
    y_concat.append(
        timeit.timeit(lambda: test_concat_chunk(seq, chunk_size), number=n) / n)
    y_stringio.append(
        timeit.timeit(lambda: test_stringio_chunk(seq, chunk_size), number=n) / n)
    y_join.append(
        timeit.timeit(lambda: test_join_chunk(seq, chunk_size), number=n) / n)
plt.plot(x, y_concat)
plt.plot(x, y_stringio)
plt.plot(x, y_join)
plt.legend(['concat', 'stringio', 'join'], loc='upper left')
plt.show()

মাইক্রো-বেঞ্চমার্ক


5

আপনি বিভিন্ন উপায়ে করতে পারেন।

str1 = "Hello"
str2 = "World"
str_list = ['Hello', 'World']
str_dict = {'str1': 'Hello', 'str2': 'World'}

# Concatenating With the + Operator
print(str1 + ' ' + str2)  # Hello World

# String Formatting with the % Operator
print("%s %s" % (str1, str2))  # Hello World

# String Formatting with the { } Operators with str.format()
print("{}{}".format(str1, str2))  # Hello World
print("{0}{1}".format(str1, str2))  # Hello World
print("{str1} {str2}".format(str1=str_dict['str1'], str2=str_dict['str2']))  # Hello World
print("{str1} {str2}".format(**str_dict))  # Hello World

# Going From a List to a String in Python With .join()
print(' '.join(str_list))  # Hello World

# Python f'strings --> 3.6 onwards
print(f"{str1} {str2}")  # Hello World

নিম্নলিখিত নিবন্ধগুলির মাধ্যমে আমি এই সামান্য সংক্ষিপ্তসারটি তৈরি করেছি।


3

আমার ব্যবহারের ক্ষেত্রে কিছুটা আলাদা ছিল। আমাকে একটি কোয়েরি তৈরি করতে হয়েছিল যেখানে আরও 20 টি ক্ষেত্র গতিশীল ছিল। আমি ফর্ম্যাট পদ্ধতিটি ব্যবহার করার এই পদ্ধতির অনুসরণ করেছি

query = "insert into {0}({1},{2},{3}) values({4}, {5}, {6})"
query.format('users','name','age','dna','suzan',1010,'nda')

এটি আমার কাছে + বা অন্যান্য উপায়ে ব্যবহার করার পরিবর্তে তুলনামূলক সহজ ছিল


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