একটি list হলো ক্রমে সাজানো আইটেমের একটি মিউটেবল কালেকশন। বেশিরভাগ কালেকশনের মতোই (দেখুন বিল্ট-ইন tuple, dict আর set), অ্যারে যেকোনো (বা একাধিক) ডেটা টাইপের রেফারেন্স ধরে রাখতে পারে, এমনকি অন্য অ্যারেও। Python-এ এদের সিকোয়েন্স ধরা হয়, আর স্লাইস নোটেশন দিয়ে এদের সম্পূর্ণ বা আংশিক কপি করা যায়।
যেকোনো সিকোয়েন্সের মতোই, lists-এর ভেতরের এলিমেন্টগুলোকে বাম দিক থেকে 0-based index সংখ্যা দিয়ে, বা ডান দিক থেকে -1-based index সংখ্যা দিয়ে রেফার করা যায়।
অ্যারে একইসাথে কমন ও মিউটেবল সিকোয়েন্স অপারেশন সমর্থন করে, যেমন min(<list>)/max(<list>), <list>.index(), <list>.append() আর <list>.reverse()। for item in <list> কাঠামো ব্যবহার করে আইটেমগুলোর উপর ইটারেশন করা যায়, আর এলিমেন্ট ও এলিমেন্ট ইনডেক্স দুটোই দরকার হলে for index, item in enumerate(<list>)।
Python অ্যারে নিয়ে কাজ করার জন্য অনেকগুলো কার্যকর মেথড দেয়।
যেহেতু অ্যারে মিউটেবল, তাই অ্যারের মেথডগুলো মেথডে পাস করা আসল অ্যারে অবজেক্টটিই বদলে দেয়। মিউটেশন না চাইলে, slice বা <list>.copy() দিয়ে আসল list অবজেক্টের (অন্ততপক্ষে) একটি shallow copy তৈরি করতে হবে।
বিদ্যমান অ্যারের শেষে আইটেম যোগ করা যায় <list>.append(<item>) দিয়ে:
>>> numbers = [1, 2, 3]
>>> numbers.append(9)
>>> numbers
[1, 2, 3, 9]
অ্যাপেন্ড করার বদলে <list>.insert(<index>, <item>) আইটেমটিকে অ্যারের ভেতরে একটি নির্দিষ্ট ইনডেক্সে যোগ করে। <index> হলো সেই আইটেমের ইনডেক্স, যার আগে আপনি নতুন আইটেমটি দেখতে চান। <item> হলো যে এলিমেন্টটি যোগ করতে চান।
লক্ষ্য করুন: <index> যদি 0 হয়, আইটেমটি অ্যারের একেবারে শুরুতে যোগ হবে। <index> যদি অ্যারের শেষ ইনডেক্সের চেয়ে বড় হয়, তবে আইটেমটি শেষ অবস্থানেই যোগ হবে, যা <list>.append(<item>) ব্যবহার করার সমান।
>>> numbers = [1, 2, 3]
>>> numbers.insert(0, -2)
>>> numbers
[-2, 1, 2, 3]
>>> numbers.insert(1, 0)
>>> numbers
[-2, 0, 1, 2, 3]
<list>.extend(<iterable>) দিয়ে একটি iterable বিদ্যমান অ্যারের সাথে একত্রিত করা যায় (দুটোকে পরপর জোড়া লাগিয়ে)। <list>.extend(<iterable>) প্রদত্ত ইটারেবলটি আনপ্যাক করে, তার এলিমেন্টগুলো একই ক্রমে টার্গেট অ্যারের শেষে যোগ করে। এই পরিস্থিতিতে <list>.append(<item>) ব্যবহার করলে পুরো ইটারেবলটিই একটিমাত্র আইটেম হিসেবে যোগ হতো।
>>> numbers = [1, 2, 3]
>>> other_numbers = [5, 6, 7]
>>> numbers.extend(other_numbers)
>>> numbers
[1, 2, 3, 5, 6, 7]
>>> numbers.extend([8, 9])
>>> numbers
[1, 2, 3, 5, 6, 7, 8, 9]
<list>.remove(<item>) দিয়ে অ্যারে থেকে একটি এলিমেন্ট মুছে ফেলা যায়। এলিমেন্টটি অ্যারেতে না থাকলে <list>.remove(<item>) একটি ValueError ছুড়ে দেবে।
>>> numbers = [1, 2, 3]
>>> numbers.remove(2)
>>> numbers
[1, 3]
# Trying to remove a value that is not in the list throws a ValueError.
>>> numbers.remove(0)
ValueError: list.remove(x): x not in list
অন্যদিকে <list>.pop(<index>) মেথড ব্যবহার করলে একটি এলিমেন্ট একইসাথে সরানো ও ব্যবহারের জন্য return করা হয়।
<list>.pop(<index>) একটি ঐচ্ছিক প্যারামিটার নেয়: যে এলিমেন্টটি সরিয়ে রিটার্ন করতে চান তার index। ঐচ্ছিক <index> আর্গুমেন্টটি না দিলে অ্যারের শেষ এলিমেন্টটি সরানো ও রিটার্ন করা হবে। <index> যদি অ্যারের শেষ ইনডেক্সের চেয়ে বড় সংখ্যা হয়, তবে একটি IndexError ছুড়ে দেওয়া হবে।
>>> numbers = [1, 2, 3]
>>> numbers.pop(0)
1
>>> numbers
[2, 3]
>>> numbers.pop()
3
>>> numbers
[2]
# This will throw an error because there is only index 0.
>>> numbers.pop(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: pop index out of range
<list>.clear() দিয়ে একটি list থেকে সব আইটেম মুছে ফেলা যায়। এটি কোনো প্যারামিটার নেয় না।
>>> numbers = [1, 2, 3]
>>> numbers.clear()
>>> numbers
[]
<list>.reverse() দিয়ে অ্যারের এলিমেন্টগুলোর ক্রম ইন-প্লেস উল্টে দেওয়া যায়। এটি আসল অ্যারেটি মিউটেট করে।
>>> numbers = [1, 2, 3]
>>> numbers.reverse()
>>> numbers
[3, 2, 1]
<list>.sort()-এর সাহায্যে একটি অ্যারে ইন-প্লেস পুনর্বিন্যাস করা যায়। ডিফল্ট সাজানোর ক্রম বাম দিক থেকে ঊর্ধ্বক্রমে। Python-এর ডকুমেন্টেশনে সাজানোর জন্য আরও টিপস ও কৌশল আছে।
২০০২ থেকে ২০২২ সাল পর্যন্ত Python ভেতরে ভেতরে অ্যারে সাজানোর জন্য Timsort নামের একটি অ্যালগরিদম ব্যবহার করত, কিন্তু Python 3.11 থেকে Powersort ব্যবহার শুরু করে।
এই পরিবর্তন নিয়ে core Python টিমের আরও বিস্তারিত আলোচনা GitHub-এর issue 78742-এ পড়তে পারেন।
অ্যালগরিদমের কারিগরি বিস্তারিত জানতে দেখুন J. Ian Munro ও Sebastian Wild-এর গবেষণাপত্র Nearly-Optimal Mergesorts: Fast, Practical Sorting Methods That Optimally Adapt to Existing Runs
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
# The default sort order is *ascending*.
>>> names.sort()
>>> names
["Bruce", "Natasha", "Thor", "Tony"]
কোনো অ্যারে অধঃক্রমে সাজাতে মেথডটিতে একটি reverse=True আর্গুমেন্ট পাস করুন:
>>> names = ["Tony", "Natasha", "Thor", "Bruce"]
>>> names.sort(reverse=True)
>>> names
["Tony", "Thor", "Natasha", "Bruce"]
আসল list মিউটেট করতে না চাইলে বিল্ট-ইন ফাংশন sorted() ও reversed() ব্যবহার করা যায়। sorted(<list>) একটি সাজানো কপি রিটার্ন করে, আর <list>.sort() যেমন প্যারামিটার নেয়, একই প্যারামিটার নেয়। reversed(<list>) একটি ইটারেটর রিটার্ন করে, যা অ্যারের আইটেমগুলো উল্টো ক্রমে দেয়। Iterators নিয়ে বিস্তারিত আলোচনা অন্য একটি অনুশীলনীতে থাকবে।
<list>.count(<item>) ব্যবহার করে অ্যারেতে একটি এলিমেন্ট কতবার আছে তা বের করা যায়। এটি অ্যারেতে <item> এলিমেন্ট হিসেবে মোট কতবার আছে, সেই সংখ্যা রিটার্ন করে।
>>> items = [1, 4, 7, 8, 2, 9, 2, 1, 1, 0, 4, 3]
>>> items.count(1)
3
<list>.index(<item>) পাস করা আইটেমটির প্রথম উপস্থিতির ইনডেক্স নম্বর রিটার্ন করে। একবারও না থাকলে একটি ValueError ছুড়ে দেওয়া হয়। ইনডেক্সিং বাম দিক থেকে 0-based, অর্থাৎ প্রথম আইটেমের অবস্থান ইনডেক্স 0। ডান দিক থেকেও ইনডেক্সিং করা যায়, যা ইনডেক্স -1 থেকে শুরু হয়।
>>> items = [7, 4, 1, 0, 2, 5]
>>> items.index(4)
1
>>> items.index(10)
ValueError: 10 is not in list
start ও end ইনডেক্স দিলে অ্যারের একটি নির্দিষ্ট অংশের ভেতরে খোঁজা হবে:
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> names.index("Tina")
0
>>> names.index("Tina", 2, 5)
3
এলিমেন্টের সঠিক অবস্থান জানার দরকার না থাকলে, সদস্যপদ যাচাই করার জন্য বিল্ট-ইন in অপারেটর বেশি কার্যকর।
>>> names = ["Tina", "Leo", "Thomas", "Tina", "Emily", "Justin"]
>>> "Thomas" in names
True
মনে রাখবেন, Python-এ ভ্যারিয়েবল হলো এমন নাম, যা ভেতরের অবজেক্টগুলোকে দেখায়। একটি প্রোগ্রামের জীবনকালে নামগুলোকে বিভিন্ন অবজেক্টে বাইন্ড বা রি-বাইন্ড করা যায়। একটি list অবজেক্টকে নতুন একটি ভ্যারিয়েবল নামে অ্যাসাইন করলে অবজেক্টটি বা তার রেফার করা কোনো ডেটা কপি হয় না। নতুন নাম ও পুরনো নাম দুটোই একই list অবজেক্টের দিকে দেখায়। এর বাইরে, অ্যারে হলো কনটেইনার ধরনের অবজেক্ট; জায়গা বাঁচাতে কনটেইনার নিজে আইটেম ধরে না, শুধু সদস্য আইটেমগুলোর রেফারেন্স ধরে রাখে। এই "অপটিমাইজেশন" সতর্ক না থাকলে অপ্রত্যাশিত পরিণতি ডেকে আনতে পারে।
<list>.copy() একটি নতুন list অবজেক্ট তৈরি করবে, কিন্তু রেফার করা অ্যারের এলিমেন্টগুলোর জন্য নতুন অবজেক্ট তৈরি করবে না; কপিটি "শ্যালো"। একটি list অবজেক্টে আইটেম যোগ বা বাদ দিতে চাইলে, আর অন্যটি অপরিবর্তিত রাখতে চাইলে, সাধারণত একটি shallow copy করাই যথেষ্ট। কিন্তু কোনো list অবজেক্টের ভেতরের এলিমেন্টগুলো ভুলে মিউটেট হয়ে যাওয়ার (আর তার ফলে সম্পর্কিত সব শ্যালো কপিও মিউটেট হয়ে যাওয়ার) সামান্য সম্ভাবনাও থাকলে, সমস্ত রেফারেন্স ও অবজেক্টের একটি সম্পূর্ণ বা "ডিপ" কপি তৈরি করতে copy মডিউলের copy.deepcopy() ব্যবহার করা উচিত।
নাম, মান, অ্যারে ও নেস্টেড অ্যারের আচরণ নিয়ে বিস্তারিত ব্যাখ্যার জন্য Ned Batchelder-এর এই চমৎকার ব্লগ পোস্টটি দেখুন: Names and values: making a game board। কপি নিয়ে ভাবার বিষয়গুলো নিয়েও ভালো একটি আলোচনা আছে Shallow vs Deep Copying of Python Objects পোস্টে।