লিস্ট সাজানো আর তার মেথডগুলো
sorted() আর .sort()-এর পার্থক্য, max/min/sum/count/index, key= দিয়ে সাজানোর নিয়ম বদলানো, আর join() দিয়ে লিস্টকে পড়ার মতো স্ট্রিং বানানো।
কীভাবে শিখতে চান?
যে সমস্যাটা আমরা সমাধান করছি
সাতজনের নম্বর একটি লিস্টে আছে। তিনটি প্রশ্নের উত্তর দিতে হবে: সবচেয়ে বেশি কত, গড় কত, আর সেরা তিনজন কারা?
গত অধ্যায়ের হাতিয়ার দিয়ে প্রথম দুটোর উত্তর লুপ লিখে বের করা যায় — কষ্টসাধ্য, কিন্তু সম্ভব। তৃতীয়টা আলাদা। “সেরা তিনজন” মানে আগে সাজাতে হবে, আর সাজানোর কোনো উপায় আমাদের এখনো নেই।
এই কাজগুলো এত ঘন ঘন লাগে যে পাইথন সেগুলো নিজেই দিয়ে রেখেছে। আজকের অধ্যায় সেই তালিকাটা — আর তার সাথে একটি ফাঁদ যা প্রায় সবাই অন্তত একবার পড়ে: একই কাজের দুটি রূপ আছে, একটি লিস্টটাকে বদলায় আর অন্যটি নতুন একটি ফেরত দেয়, আর ভুলটা বেছে নিলে কোনো এরর হয় না।
এই অধ্যায় শেষে আপনি পারবেন
sorted()আর.sort()-এর পার্থক্য বলতে, আর কোনটি কখন লাগে জানতেmax,min,sum,count,indexদিয়ে লিস্ট থেকে উত্তর বের করতেkey=দিয়ে সাজানোর নিয়ম বদলাতেjoin()দিয়ে একটি লিস্টকে পড়ার মতো স্ট্রিং-এ পরিণত করতে- মেশানো ধরনের লিস্ট সাজাতে গেলে কেন
TypeErrorহয়, বলতে
আগে যা জানা লাগবে: লিস্ট — একই নামে অনেকগুলো মান।
sorted() আর .sort() — এই অধ্যায়ের মূল কথা
দুটোই সাজায়। পার্থক্য হলো কী নিয়ে ফিরে আসে।
marks = [72, 45, 90, 61]
ordered = sorted(marks)
print(ordered)
print(marks)
marks.sort()
print(marks)[45, 61, 72, 90]
[72, 45, 90, 61]
[45, 61, 72, 90]তিনটি লাইন মন দিয়ে পড়ুন।
sorted(marks) একটি নতুন সাজানো লিস্ট বানিয়ে ফেরত দিয়েছে। মূল marks অবিকল আগের মতোই রয়ে গেছে — দ্বিতীয় লাইনটাই তার প্রমাণ।
marks.sort() কোনো নতুন লিস্ট বানায়নি। সে মূল লিস্টটাকেই সাজিয়ে দিয়েছে, আর পুরোনো ক্রমটা চিরতরে হারিয়ে গেছে।
গত অধ্যায়ের নিয়মটাই এখানে ফিরে এসেছে: যে মেথড লিস্টটাকে বদলায়, সে কিছু ফেরত দেয় না।
marks = [72, 45, 90, 61]
marks = marks.sort()
print(marks)Noneappend-এর মতোই। .sort() লিখলে ফলটা ধরতে নেই; sorted() লিখলে ফলটা না ধরলে কাজটাই বৃথা।
কোনটা কখন? মূল ক্রমটা আর দরকার না হলে .sort() সহজ ও সস্তা। মূল লিস্টটা অন্য কোথাও ব্যবহৃত হচ্ছে, বা আপনি নিশ্চিত নন — তখন sorted(), কারণ সে কারও কিছু কেড়ে নেয় না। সন্দেহ হলে sorted()।
উল্টো ক্রম আর সংখ্যার উত্তর
marks = [72, 45, 90, 61]
print(sorted(marks, reverse=True))
print(max(marks), min(marks), sum(marks))
print(round(sum(marks) / len(marks), 2))[90, 72, 61, 45]
90 45 268
67.0max, min, sum — তিনটিই ফাংশন, মেথড নয়, তাই marks.max() নয় বরং max(marks)। গড়ের জন্য আলাদা কিছু নেই: যোগফলকে সংখ্যা দিয়ে ভাগ করাই গড়, আর round(..., 2) দেখানোর জন্য দুই ঘরে নামিয়ে আনে।
খেয়াল করুন ১০ নম্বর অধ্যায়ের লুপ দিয়ে জমানোর কাজটা এখানে এক লাইনে হয়ে গেল। লুপটা শেখা বৃথা যায়নি — sum যে কাজটা করছে সেটা ঠিক ওই লুপই, আর কোনো দিন এমন কিছু জমাতে হবে যার জন্য পাইথনের তৈরি ফাংশন নেই।
গোনা আর খোঁজা
marks = [72, 45, 90, 45, 61]
print(marks.count(45))
print(marks.index(45))
print(marks.index(90))2
1
2count(x) বলে x কতবার আছে। index(x) বলে প্রথম কোথায় আছে — দুটো 45 থাকলেও সে প্রথমটির ইনডেক্স 1 দেয়, দ্বিতীয়টির কথা বলে না।
আর নেই এমন কিছু খুঁজলে index থেমে যায়:
marks = [72, 45, 90]
print(marks.index(50))ValueError: 50 is not in listremove-এর মতোই। আগে if 50 in marks: দিয়ে দেখে নেওয়া অভ্যাস করুন।
স্ট্রিং সাজানো, আর key=
names = ["rafi", "Bilal", "ahmed"]
print(sorted(names))
print(sorted(names, key=str.lower))['Bilal', 'ahmed', 'rafi']
['ahmed', 'Bilal', 'rafi']প্রথম ফলটা দেখে অনেকে ভাবে পাইথন ভুল করেছে। করেনি — সে অক্ষরের কোড নম্বর ধরে সাজায়, আর সেখানে সব বড় হাতের অক্ষর সব ছোট হাতের অক্ষরের আগে আসে। তাই Bilal চলে গেছে সবার আগে।
key=str.lower বলছে: সাজানোর সময় প্রতিটি নামকে ছোট হাতের ভেবে নাও। নামগুলো বদলায় না — ছাপা ফলে Bilal-এ বড় হাতের B ঠিকই আছে — শুধু তুলনা করার সময় ছোট হাতের রূপটা ব্যবহৃত হয়।
key যেকোনো নিয়ম হতে পারে:
words = ["bag", "pen", "notebook", "ink"]
print(sorted(words, key=len))['bag', 'pen', 'ink', 'notebook']দৈর্ঘ্য ধরে সাজানো। খেয়াল করুন bag, pen, ink তিনটিরই দৈর্ঘ্য তিন, আর তারা যে ক্রমে ছিল সেই ক্রমেই রয়ে গেছে — সমান হলে পাইথন ক্রম নষ্ট করে না। এই বৈশিষ্ট্যটির নাম stable sort, আর একাধিক শর্তে সাজানোর সময় এটিই কাজে লাগে।
মেশানো ধরন সাজানো যায় না
values = [3, "1", 2]
print(sorted(values))TypeError: '<' not supported between instances of 'str' and 'int'সাজাতে হলে জোড়ায় জোড়ায় তুলনা করতে হয়, আর ৮ নম্বর অধ্যায়ে দেখেছিলাম একটি সংখ্যা আর একটি স্ট্রিং < দিয়ে তুলনা করা যায় না। বার্তাটি তাই হুবহু সেই একই বার্তা। CSV ফাইল থেকে পড়া লিস্টে এটি নিয়মিত ঘটে — সেখানে সব সংখ্যাই আসলে স্ট্রিং।
লিস্ট থেকে স্ট্রিং — join
লিস্ট সরাসরি ছাপলে স্কয়ার ব্র্যাকেট আর কোটেশনসহ আসে, যা মানুষকে দেখানোর জন্য নয়:
names = ["rafi", "ahmed", "bilal"]
print(", ".join(names))
print(" | ".join(names))rafi, ahmed, bilal
rafi | ahmed | bilalলাইনটা প্রথমবার উল্টো লাগে: জোড়া লাগানোর চিহ্নটা আগে বসে, আর লিস্টটা ব্র্যাকেটের ভেতরে। মনে রাখার উপায় — “এই চিহ্ন দিয়ে এদের জুড়ে দাও”।
একটাই শর্ত, আর সেটি কড়া: সব মান স্ট্রিং হতে হবে।
marks = [72, 45, 90]
print(", ".join(marks))TypeError: sequence item 0: expected str instance, int foundসংখ্যার লিস্ট জোড়া লাগাতে হলে আগে প্রতিটিকে স্ট্রিং-এ বদলে নিতে হয়:
marks = [72, 45, 90]
print(", ".join(str(m) for m in marks))72, 45, 90str(m) for m in marks লেখাটা নতুন, আর এটা পুরোপুরি শেখানো হবে সামনের একটা অধ্যায়ে। আপাতত শুধু এভাবে পড়ুন: “marks-এর প্রতিটি m-কে str(m) বানাও।” তারপর join সেই স্ট্রিংগুলো জুড়ে দেয়। নিচের সম্পূর্ণ উদাহরণেও একই লাইন আছে।
একটা সম্পূর্ণ উদাহরণ
report.py:
# A marks report: order them, summarise them, and show the top three
marks = [72, 45, 90, 61, 88, 45, 33]
ordered = sorted(marks, reverse=True)
print("Marks :", marks)
print("Ordered :", ordered)
print("Count :", len(marks))
print("Highest :", max(marks))
print("Lowest :", min(marks))
print("Total :", sum(marks))
print("Average :", round(sum(marks) / len(marks), 2))
print("How many 45s:", marks.count(45))
top_three = ordered[:3]
print("Top three:", top_three)
print("As text :", ", ".join(str(m) for m in top_three))
passed = []
for mark in marks:
if mark >= 40:
passed.append(mark)
print("Passed :", len(passed), "of", len(marks))Marks : [72, 45, 90, 61, 88, 45, 33]
Ordered : [90, 88, 72, 61, 45, 45, 33]
Count : 7
Highest : 90
Lowest : 33
Total : 434
Average : 62.0
How many 45s: 2
Top three: [90, 88, 72]
As text : 90, 88, 72
Passed : 6 of 7দুটো ডিজাইনের সিদ্ধান্ত খেয়াল করুন।
sorted() বেছে নেওয়া হয়েছে, .sort() নয় — কারণ প্রথম লাইনেই মূল marks আবার ছাপা হচ্ছে। .sort() লিখলে “Marks” আর “Ordered” দুটো লাইনই একই দেখাত, আর কেউ এরর দেখাত না। এটাই সেই নীরব ভুল যা এই অধ্যায়ের শুরুতে বলা হয়েছিল।
সেরা তিনজন বের হয়েছে স্লাইস দিয়ে — ordered[:3]। আলাদা কোনো “শীর্ষ তিন” ফাংশন লাগেনি: উল্টো ক্রমে সাজানো লিস্টের প্রথম তিনটিই সেরা তিনটি। সাজানোর পর বহু প্রশ্নের উত্তর এভাবে একটি স্লাইস হয়ে যায়।
কিছু ভাঙা অবস্থা ও তার সমাধান
.sort() করার পর লিস্টটা None হয়ে গেছে marks = marks.sort() লেখা হয়েছে। .sort() লিস্টটাকেই সাজায় আর None ফেরত দেয় — শুধু marks.sort() লিখুন। নতুন একটি লিস্ট চাইলে ordered = sorted(marks)।
সাজানোর পর মূল লিস্টটাও বদলে গেছে .sort() ব্যবহার করা হয়েছে, যা মূল লিস্টকেই সাজায়। মূলটা অক্ষত রাখতে sorted() ব্যবহার করুন।
TypeError: '<' not supported between instances of 'str' and 'int' লিস্টে সংখ্যা আর স্ট্রিং মেশানো। print(marks) করে দেখুন কোনগুলো কোটেশনের ভেতরে; ফাইল থেকে পড়া হলে সাধারণত সবই স্ট্রিং, আর int() দিয়ে বদলে নিতে হয়।
ValueError: 50 is not in list index() বা remove()-কে এমন একটি মান দেওয়া হয়েছে যা লিস্টে নেই। আগে in দিয়ে দেখে নিন।
TypeError: sequence item 0: expected str instance, int found join()-কে সংখ্যার লিস্ট দেওয়া হয়েছে। প্রতিটিকে str() করে নিন।
নাম সাজানোর পর বড় হাতের নামগুলো সব আগে চলে এসেছে এটাই স্বাভাবিক আচরণ, এরর নয়। মানুষের প্রত্যাশা মতো সাজাতে sorted(names, key=str.lower)।
ধাপ ৪ / ৬ — অনুমান
যাচাই করুন
sorted() ব্যবহার করা হয়েছে। দুটি লাইন কী ছাপবে?
marks = [72, 45, 90]
ordered = sorted(marks)
print(ordered)
print(marks)- A[45, 72, 90] [72, 45, 90]
- B[45, 72, 90] None
- C[45, 72, 90] [45, 72, 90]
- D[72, 45, 90] [45, 72, 90]
.sort()-এর ফলটি আবার marks-এ বসানো হয়েছে। কী ছাপা হবে?
marks = [72, 45, 90]
marks = marks.sort()
print(marks)- Aএকটি `AttributeError`
- B[72, 45, 90]
- C[45, 72, 90]
- DNone
সংখ্যার একটি লিস্টকে কমা দিয়ে জোড়া লাগানোর চেষ্টা। কী হবে?
marks = [72, 45, 90]
print(", ".join(marks))- A`TypeError` — `join` শুধু স্ট্রিং জোড়া লাগাতে পারে
- B724590
- C72, 45, 90
- D[72, 45, 90]
উত্তর দিতে অ্যাকাউন্ট লাগবে
উত্তর মিলিয়ে দেখতে সাইন ইন করুন
প্রশ্নগুলো উপরে আছে, আর মাথায় মাথায় উত্তর ভেবে নেওয়াই আসল কাজ। সঠিক উত্তর, ব্যাখ্যা আর তিন ধাপের ইঙ্গিত দেখতে সাইন ইন করুন।
নিজে করুন
inventory.py নামে একটি ফাইল লিখুন, যেখানে অন্তত সাতটি পণ্যের নামের একটি লিস্ট আর তাদের দামের একটি লিস্ট থাকবে।
দামের লিস্টটি নিয়ে ছাপান:
- সবচেয়ে বেশি, সবচেয়ে কম, যোগফল আর গড় (গড় দুই ঘর পর্যন্ত)
- সাজানো একটি নতুন লিস্ট — আর তারপর প্রমাণ করুন মূল লিস্টটি বদলায়নি
- সবচেয়ে দামি তিনটি, স্লাইস দিয়ে
নামের লিস্টটি নিয়ে ছাপান:
- বর্ণানুক্রমে সাজানো, ছোট-বড় হাতের অক্ষর উপেক্ষা করে
- নামের দৈর্ঘ্য ধরে সাজানো
- সব নাম একটি লাইনে, কমা দিয়ে আলাদা করে —
joinদিয়ে
শেষে একটি পরীক্ষা করুন: দামের লিস্টে .sort() চালান, তারপর আবার ১ নম্বরের লাইনগুলো ছাপান। কোন সংখ্যাটা বদলে গেল, আর কোনটা গেল না? যেগুলো বদলায়নি তারা কেন বদলায়নি, সেটা নিজেকে বুঝিয়ে বলুন — উত্তরটা মনে থাকলে এই অধ্যায়ের ফাঁদটা আপনাকে আর ধরতে পারবে না।
ধাপ ৬ / ৬
কঠিন করা — অধ্যায়ের কুইজ
সহজ থেকে কঠিন — দশটি প্রশ্ন, শেষেরগুলো ইচ্ছে করেই কঠিন।
সাইন ইন করে কুইজ দিন