.NET- এ স্ট্রিংগুলি অপরিবর্তনীয়, এমনটি বিবেচনা করে আমি ভাবছি যে কেন সেগুলি এমনভাবে তৈরি করা হয়েছে যাতে পরিবর্তে string.Substring()
ও ( substring.Length
) সময় লাগে O(1)
?
অর্থাত্ যদি কোন ট্রেড অফস ছিল তবে?
.NET- এ স্ট্রিংগুলি অপরিবর্তনীয়, এমনটি বিবেচনা করে আমি ভাবছি যে কেন সেগুলি এমনভাবে তৈরি করা হয়েছে যাতে পরিবর্তে string.Substring()
ও ( substring.Length
) সময় লাগে O(1)
?
অর্থাত্ যদি কোন ট্রেড অফস ছিল তবে?
উত্তর:
আপডেট: আমি এই প্রশ্নটি খুব পছন্দ করেছিলাম, আমি কেবল এটি ব্লগ করেছি। দেখুন স্ট্রিং, অপরিবর্তনীয়তা এবং অধ্যবসায়
সংক্ষিপ্ত উত্তরটি হ'ল: ও (এন) হ'ল হ'ল (1) যদি n বড় না হয়। বেশিরভাগ লোকেরা ক্ষুদ্রতর স্ট্রিংগুলি থেকে ক্ষুদ্র সাবস্ট্রিংগুলি বের করে, যাতে জটিলতা কীভাবে asympototically বৃদ্ধি পায় তা সম্পূর্ণ অপ্রাসঙ্গিক ।
দীর্ঘ উত্তর:
একটি অপরিবর্তনীয় ডেটা স্ট্রাকচার যেমন একটি উদাহরণস্বরূপ অপারেশনগুলিকে অনুলিপি বা নতুন বরাদ্দের কেবল অল্প পরিমাণে (সাধারণত ও (1) বা ও (এলজি এন)) পুনরায় ব্যবহারের অনুমতি দেয় " অপরিবর্তনীয় ডেটা স্ট্রাকচার। .NET এর স্ট্রিংগুলি পরিবর্তনযোগ্য; আপনার প্রশ্নটি মূলত "কেন তারা অবিচল থাকে না"?
কারণ আপনি যখন .NET প্রোগ্রামগুলিতে স্ট্রিংগুলিতে সাধারণত করা অপারেশনগুলি দেখেন , কেবলমাত্র পুরোপুরি নতুন স্ট্রিং তৈরি করা কোনও প্রাসঙ্গিক উপায়েই খুব খারাপ হয় । জটিল ধ্রুবক ডেটা কাঠামো তৈরির ব্যয় এবং অসুবিধা নিজের জন্য অর্থ প্রদান করে না।
লোকেরা সাধারণত একটি সংক্ষিপ্ত স্ট্রিং বের করার জন্য "সাবস্ট্রিং" ব্যবহার করে - বলুন, দশ বা বিশটি অক্ষর - কিছুটা দীর্ঘ স্ট্রিংয়ের মধ্যে - সম্ভবত কয়েকশত অক্ষর। কমা-বিচ্ছিন্ন ফাইলটিতে আপনার পাঠ্যের একটি লাইন রয়েছে এবং আপনি তৃতীয় ক্ষেত্রটি বের করতে চান, এটি একটি শেষ নাম। লাইনটি কয়েক শ অক্ষর দীর্ঘ হতে পারে, নামটি কয়েক ডজন হবে। স্ট্রিং বরাদ্দ এবং মেমরির পঞ্চাশ বাইট কপি করা আধুনিক হার্ডওয়্যারটিতে আশ্চর্যজনকভাবে দ্রুত । একটি নতুন ডাটা স্ট্রাকচার একটি বিদ্যমান স্ট্রিং এর মধ্য একটি পয়েন্টার নিয়ে গঠিত প্লাস একটি দৈর্ঘ্য হল উপার্জন যে এছাড়াও কাজে অবিশ্বাস্য দ্রুত অপ্রাসঙ্গিক; "দ্রুত যথেষ্ট" সংজ্ঞা দ্বারা দ্রুত যথেষ্ট।
উত্তোলিত সাবস্ট্রিংগুলি সাধারণত আকারে ছোট এবং আজীবন সংক্ষিপ্ত; আবর্জনা সংগ্রহকারী শীঘ্রই তাদের পুনরায় দাবি করতে চলেছে, এবং তারা প্রথমে স্তূপে খুব বেশি জায়গা নেয়নি। সুতরাং বেশিরভাগ স্মৃতির পুনরায় ব্যবহারকে উত্সাহিত করে এমন একটি অবিরাম কৌশল ব্যবহার করাও জয় নয়; আপনার সমস্ত কিছুই আপনার আবর্জনা সংগ্রাহককে ধীর করে তুলছে কারণ এখন এটি অভ্যন্তর পয়েন্টারগুলি পরিচালনা করার বিষয়ে চিন্তা করতে হবে।
যদি স্ট্রিংিং অপারেশনগুলি লোকেরা সাধারণত স্ট্রিংগুলিতে করে থাকে তবে তা সম্পূর্ণ আলাদা ছিল, তবে অবিচ্ছিন্ন পদ্ধতির সাথে যাওয়া অর্থহীন। যদি লোকেরা সাধারণত মিলিয়ন-চরিত্রের স্ট্রিংগুলি রাখে এবং এক লক্ষ-হাজার-চরিত্রের সীমার মধ্যে হাজার হাজার ওভারল্যাপিং সাবস্ট্রিংগুলি বের করে নিয়েছিল এবং সেই সাবস্ট্রিংগুলি স্তূপে দীর্ঘকাল বেঁচে থাকে, তবে এটি একটি অবিচ্ছিন্ন সাবস্ট্রিংয়ের সাথে যাওয়ার জন্য সঠিক ধারণা তৈরি করতে পারে কাছে; এটা অপব্যয় এবং বোকামি হবে না। তবে বেশিরভাগ লাইন-বিজনেস প্রোগ্রামাররা এই ধরণের জিনিসগুলির মতো অস্পষ্টভাবে কিছু করে না। .NET এমন একটি প্ল্যাটফর্ম নয় যা হিউম্যান জিনোম প্রকল্পের প্রয়োজন অনুসারে তৈরি করা হয়; ডিএনএ বিশ্লেষণ প্রোগ্রামারদের প্রতিদিন সেই স্ট্রিং ব্যবহারের বৈশিষ্ট্যগুলির সাথে সমস্যাগুলি সমাধান করতে হবে; প্রতিক্রিয়া ভাল যে আপনি না। কিছু যারা তাদের নিজস্ব দৃistent় ডেটা স্ট্রাকচার তৈরি করেন যা তাদের ব্যবহারের দৃশ্যের সাথে ঘনিষ্ঠভাবে মেলে ।
উদাহরণস্বরূপ, আমার দল এমন প্রোগ্রাম লিখেছে যা আপনি টাইপ করার সাথে সাথে সি # এবং ভিবি কোডের অন ফ্লাইট বিশ্লেষণ করে। এই কোডগুলির কয়েকটি ফাইল প্রচুর এবং সুতরাং আমরা সাবস্ট্রিংগুলি নিষ্কাশন করতে বা অক্ষরগুলি সন্নিবেশ করানোর জন্য বা মুছতে O (n) স্ট্রিং ম্যানিপুলেশন করতে পারি না। আমরা একটি টেক্সট বাফারে সম্পাদনাগুলি উপস্থাপনের জন্য অবিচ্ছিন্ন অপরিবর্তনীয় ডেটা স্ট্রাকচার তৈরি করেছি যা আমাদের কাছে বিদ্যমান স্ট্রিং ডেটা এবং প্রচলিত লেক্সিকাল এবং সিনট্যাকটিক বিশ্লেষণগুলি একটি সাধারণ সম্পাদনার উপর ভিত্তি করে দ্রুত এবং দক্ষতার সাথে পুনরায় ব্যবহার করার অনুমতি দেয় । এটি সমাধান করা একটি কঠিন সমস্যা ছিল এবং এর সমাধানটি সি # এবং ভিবি কোড সম্পাদনার নির্দিষ্ট ডোমেনের সাথে সংক্ষিপ্তভাবে তৈরি করা হয়েছিল। আমাদের জন্য বিল্ট-ইন স্ট্রিং টাইপটি এই সমস্যাটি সমাধান করার জন্য আশা করা অবাস্তব।
string contents = File.ReadAllText(filename); foreach (string line in content.Split("\n")) ...
বা এর অন্যান্য সংস্করণ। মানে একটি সম্পূর্ণ ফাইল পড়ুন, তারপরে বিভিন্ন অংশটি প্রক্রিয়া করুন। এই ধরণের কোডটি যথেষ্ট দ্রুত হবে এবং স্ট্রিং যদি অবিচল থাকে তবে কম মেমরির প্রয়োজন হবে; আপনার কাছে প্রতিটি লাইন অনুলিপি করার পরিবর্তে মেমরিতে ফাইলের ঠিক একটি অনুলিপি থাকত, তারপরে প্রতিটি লাইনের অংশগুলি আপনার প্রক্রিয়া হিসাবে। যাইহোক, এরিক যেমন বলেছেন - এটি সাধারণ ব্যবহারের ক্ষেত্রে নয়।
String
একটি অবিরাম ডেটা কাঠামো হিসাবে প্রয়োগ করা হয় (এটি স্ট্যান্ডার্ডগুলিতে নির্দিষ্ট করা হয়নি, তবে আমি জানি যে সমস্ত বাস্তবায়ন আমি এটি করি)।
স্পষ্টতই স্ট্রিংগুলি পরিবর্তনযোগ্য না হওয়ার কারণে.Substring
অবশ্যই মূল স্ট্রিংয়ের কমপক্ষে একটি অংশের একটি অনুলিপি তৈরি করতে হবে। এন বাইটের অনুলিপি তৈরি করতে ও (এন) সময় নেওয়া উচিত।
আপনি কীভাবে মনে করেন যে আপনি অবিচ্ছিন্ন সময়ে একগুচ্ছ বাইটগুলি অনুলিপি করবেন ?
সম্পাদনা: মেহরদাদ স্ট্রিংটি একেবারেই অনুলিপি না করার জন্য, তবে এটির একটি অংশের রেফারেন্স রাখার পরামর্শ দেয়।
নেট বিবেচনা করুন, একটি বহু-মেগাবাইট স্ট্রিং, যার উপর কেউ কল করে .SubString(n, n+3)
(স্ট্রিংয়ের মাঝখানে কোনও এন এর জন্য)।
এখন, পুরো স্ট্রিংটি আবর্জনা সংগ্রহ করা যাবে না কারণ কেবল একটি রেফারেন্স 4 টি অক্ষর ধরে রেখেছে? জায়গাটির একটি হাস্যকর বর্জ্য বলে মনে হচ্ছে এটি।
তদ্ব্যতীত, সাবস্ট্রিংগুলির রেফারেন্সগুলি ট্র্যাক করা (যা এমনকি সাবস্ট্রিংগুলির অভ্যন্তরেও থাকতে পারে), এবং জিসি (উপরে বর্ণিত হিসাবে) পরাজিত করা এড়াতে অনুকূল সময়ে অনুলিপি করার চেষ্টা করে ধারণাটিকে একটি দুঃস্বপ্ন করে তোলে। .SubString
সরাসরি অনিবার্য মডেল অনুলিপি করা এবং বজায় রাখা এটি অনেক সহজ এবং আরও নির্ভরযোগ্য ।
সম্পাদনা: বৃহত্তর স্ট্রিংয়ের মধ্যে সাবস্ট্রিংগুলিতে রেফারেন্স রাখার বিপদ সম্পর্কে এখানে খুব ভাল পড়ুন ।
memcpy
যা এখনও (ও) is
char*
সাবস্ট্রিং পেতে পারেন ।
NULL
। লিপার্টের পোস্টে যেমন ব্যাখ্যা করা হয়েছে , প্রথম 4 বাইট স্ট্রিংয়ের দৈর্ঘ্য ধারণ করে। এই কারণেই, স্কিট যেমন উল্লেখ করেছে, সেগুলিতে \0
অক্ষর থাকতে পারে ।
জাভা (.NET এর বিপরীতে) করার দুটি উপায় সরবরাহ করে Substring()
, আপনি বিবেচনা করতে পারেন আপনি কেবল একটি রেফারেন্স রাখতে চান বা একটি নতুন মেমরির স্থানে পুরো স্ট্রিংটি অনুলিপি করতে চান।
সাধারণ স্ট্রিং অবজেক্টের সাথে .substring(...)
অভ্যন্তরীণভাবে ব্যবহৃত char
অ্যারে ভাগ করে , যা আপনি new String(...)
প্রয়োজন হলে একটি নতুন অ্যারে অনুলিপি করতে পারেন (মূলের আবর্জনা সংগ্রহের বাধা এড়াতে)।
আমি মনে করি যে এই ধরণের নমনীয়তা বিকাশকারীদের পক্ষে সেরা বিকল্প।
.substring(...)
।
জাভা বড় স্ট্রিং রেফারেন্স ব্যবহৃত, কিন্তু:
আমার মনে হচ্ছে যদিও এটি উন্নত করা যেতে পারে: কেন কেবল শর্তযুক্ত অনুলিপি করা হয় না?
যদি স্ট্রিংগুলি পিতামাতার কমপক্ষে অর্ধেক আকারের হয় তবে একজন পিতামাতাকে উল্লেখ করতে পারে। অন্যথায় একজন কেবল একটি অনুলিপি তৈরি করতে পারেন। এটি এখনও একটি উল্লেখযোগ্য সুবিধা প্রদান করার সময় প্রচুর স্মৃতি ফাঁস করা এড়িয়ে যায়।
char[]
(শুরু এবং শেষের দিকে বিভিন্ন পয়েন্টার সহ) ব্যবহার করে নতুন তৈরিতে পরিবর্তিত হয়েছিল String
। এটি পরিষ্কারভাবে দেখায় যে ব্যয়-বেনিফিট বিশ্লেষণ অবশ্যই একটি নতুন তৈরির জন্য একটি অগ্রাধিকার দেখায় String
।
এখানে উত্তরগুলির মধ্যে কোনওটিই "বন্ধনী সমস্যা" কে সম্বোধন করে নি, যার অর্থ হ'ল .NET- এ স্ট্রিংগুলি একটি BStr (মেমরিতে সঞ্চিত দৈর্ঘ্য "" পয়েন্টারের আগে ") এবং একটি সিএসটিআর (স্ট্রিংটি একটিতে শেষ হয়) এর সংমিশ্রণ হিসাবে উপস্থাপিত হয় '\ 0')।
"হ্যালো সেখানে" স্ট্রিংটি যেমন উপস্থাপিত হয়
0B 00 00 00 48 00 65 00 6C 00 6F 00 20 00 74 00 68 00 65 00 72 00 65 00 00 00
(কোন নির্ধারিত char*
একটি fixed
-statement পয়েন্টার 0x48 নির্দেশ করবে।)
এই কাঠামোটি স্ট্রিংয়ের দৈর্ঘ্যের দ্রুত অনুসন্ধানের জন্য অনুমতি দেয় (অনেকগুলি ক্ষেত্রে কার্যকর) এবং পয়েন্টারটিকে পি / ইনভোকের মাধ্যমে উইন 32 (বা অন্যান্য) এপিআইগুলিতে পাস করার অনুমতি দেয় যা নাল-টার্মিনেটেড স্ট্রিংয়ের প্রত্যাশা করে।
আপনি যখন Substring(0, 5)
"ওহ করেন তবে আমি প্রতিশ্রুতি দিয়েছিলাম যে শেষ চরিত্রের পরে শূন্য চরিত্রটি থাকবে" নিয়ম বলছে আপনাকে একটি অনুলিপি তৈরি করতে হবে। এমনকি যদি আপনি শেষে স্ট্রিংিং পেয়ে থাকেন তবে অন্যান্য ভেরিয়েবলগুলি ক্ষতিগ্রস্ত না করে দৈর্ঘ্য স্থাপনের কোনও জায়গা থাকবে না।
কখনও কখনও, যদিও আপনি সত্যিই "স্ট্রিংয়ের মাঝামাঝি" সম্পর্কে কথা বলতে চান এবং আপনি পি / ইনভোক আচরণটি অগত্যা যত্নবান হন না। সদ্য সংযুক্ত ReadOnlySpan<T>
কাঠামোটি কোনও নকল অনুলিপি পেতে ব্যবহার করা যেতে পারে:
string s = "Hello there";
ReadOnlySpan<char> hello = s.AsSpan(0, 5);
ReadOnlySpan<char> ell = hello.Slice(1, 3);
ReadOnlySpan<char>
"সাবস্ট্রিং" দোকানে দৈর্ঘ্য স্বাধীনভাবে, এবং এটি গ্যারান্টি মান শেষে যে একটা '\ 0' না। এটি "স্ট্রিংয়ের মতো" বিভিন্ন উপায়ে ব্যবহার করা যেতে পারে, তবে এটি "স্ট্রিং" নয় কারণ এটিতে বিএসটিআর বা সিএসটিআর বৈশিষ্ট্য নেই (এটি উভয়ই খুব কম)। আপনি যদি কখনও (সরাসরি) পি / ইনভোক করেন না তবে তারতম্যের খুব বেশি কিছু নেই (আপনি যে API এ কল করতে চান এটির ReadOnlySpan<char>
ওভারলোড না থাকলে)।
ReadOnlySpan<char>
একটি রেফারেন্স টাইপের ক্ষেত্র হিসাবে ব্যবহার করা যায় না, সুতরাং এটিও রয়েছে ReadOnlyMemory<char>
( s.AsMemory(0, 5)
), যা একটি থাকার পরোক্ষ উপায় ReadOnlySpan<char>
, সুতরাং একই পার্থক্য- string
উপস্থিত রয়েছে।
পূর্ববর্তী উত্তরের উত্তর / মন্তব্যগুলির মধ্যে কিছু এই সম্পর্কে বর্নিত হযেছে যে আবর্জনা সংগ্রহকারীকে আপনি প্রায় 5 টি চরিত্রের বিষয়ে কথা বলার সময় অবধি একটি মিলিয়ন-চরিত্রের স্ট্রিংটি রাখতে হবে। এটি হ'ল স্পষ্টভাবে আচরণ যা আপনি ReadOnlySpan<char>
পদ্ধতির সাথে পেতে পারেন । যদি আপনি কেবল সংক্ষিপ্ত গণনা করছেন তবে কেবলমাত্র পঠনযোগ্য স্প্যান পদ্ধতিটি আরও ভাল। আপনার যদি এটির কিছুক্ষণ অবিচল থাকার প্রয়োজন হয় এবং আপনি মূল স্ট্রিংয়ের কেবলমাত্র একটি সামান্য শতাংশ রাখতে চলেছেন তবে একটি উপযুক্ত সাবস্ট্রিং (অতিরিক্ত ডেটা ছাঁটাই করতে) করা আরও ভাল। মাঝখানে কোথাও একটি রূপান্তর পয়েন্ট রয়েছে তবে এটি আপনার নির্দিষ্ট ব্যবহারের উপর নির্ভর করে।