পাইথন – ইতিহাস, বর্তমান ও ভবিষ্যৎ

প্রোগ্রামিং সম্পর্কে সামান্য ধারণা আছে, অথচ পাইথনের নাম শোনেনি এমন মানুষ বোধহয় খুঁজে পাওয়া যাবে না। বর্তমান সময়ের সবচেয়ে দ্রুত বর্ধনশীল প্রোগ্রামিং ভাষা হচ্ছে পাইথন। বাচ্চাদের প্রোগ্রামিং শেখা থেকে শুরু করে ব্যাকএন্ড ওয়েব ডেভেলপমেন্ট, বৈজ্ঞানিক গবেষণা, জটিল তথ্য বিশ্লেষণ (Complex Data Analysis), কৃত্রিম বুদ্ধিমত্তা (Artificial Intelligence) ইত্যাদিসহ আরো অনেক জায়গায় রয়েছে পাইথনের একচ্ছত্র আধিপত্য।

গিডো ফন রোসাম (Guido van Rossum) একটি ডিস্ট্রিবিউটেড সিস্টেম নিয়ে কাজ করতেন সিডাব্লিউআই-তে (Centrum Wiskunde & Informatica – CWI)। সেখানে তিনি সি ও ইউনিক্স শেল ব্যবহার করতেন। এগুলোর বিভিন্ন সীমাবদ্ধতা নিয়ে হতাশ ছিলেন তিনি। সি ভাষায় মেমোরি ব্যবস্থাপনার বিশাল ঝামেলা, প্রতি নতুন প্রজেক্টে কিছু নির্দিষ্ট কাজ বারবার করতে হতো, প্রয়োজনীয় লাইব্রেরির অভাবসহ নানা সীমাবদ্ধতা ছিল। ইউনিক্স শেল সাধারণ কাজ-কর্মের জন্য চমৎকার হলেও জটিল লজিক্যাল সমস্যা নিয়ে কাজ করার উপযুক্ত ছিল না।

তাই তিনি সিদ্ধান্ত নিলেন যে নিজেই একটি প্রোগ্রামিং ভাষা তৈরি করবেন, যা হবে সহজে ব্যবহারযোগ্য, পাঠযোগ্য ও শক্তিশালী। সিডাব্লিউআই-তে তিনি তিন বছর একটি দলের সঙ্গে কাজ করেছিলেন যারা এবিসি (ABC) নামের একটি ইন্টারপ্রেটেড ভাষা তৈরি করেছে। সেই সুবাদে তিনি ইন্টারপ্রেটার তৈরির মৌলিক বিষয়াদি শিখেছিলেন। মৌলিক বিষয়াদি জানা থাকায় তিনি সরাসরি ভাষা তৈরি করা শুরু করে দেন। এবিসি তৈরি হতে মোটামুটি তিন বছর সময় লাগলেও রোসাম মাত্র তিন মাসে পাইথনের একটা কাঠামো দাঁড় করিয়ে ফেলেন। এই তিন মাস তিনি পাইথনের পেছনে পূর্ণ সময় দিতে পারেননি। সিডাব্লিউআই-তে কাজের পাশাপাশি তিনি পাইথন প্রজেক্টে কাজ করেছেন। alt.sources নামের একটি নিউজগ্রুপে ১৯৯১ সালে তিনি প্রথম পাইথন উন্মুক্ত করেন।

পাইথনের ঐ সংস্করণে আধুনিক পাইথনের অনেক কিছুই ছিল। পরিপূর্ণ ইন্টারপ্রেটার, ডিকশনারি, টাপল, ইনডেন্টেশন সবই ছিল। অত্যাবশ্যক ইনডেন্টেশনের নিয়মটি পাইথনে যোগ করা হয়েছিল যাতে সোর্স কোড গোছানো থাকে, এর পাঠযোগ্যতা (readability) বাড়ে। অনেকেই বিষয়টির প্রশংসা করেছেন, আবার অনেকে পছন্দ করেননি। ধীরে ধীরে পাইথন ব্যবহারকারী বাড়তে থাকে, রোসামও উৎসাহ পেতে থাকেন।

রোসাম বিশ্বাস করেন যে, পাইথনের সফলতার পেছনে ডেভেলপারদের সেই মানসিকতাই কাজ করেছে, যে কারণে তিনি পাইথন তৈরি করেছিলেন। ডেভেলপাররা একটি উচ্চস্তরের স্ক্রিপ্টিং ভাষা চাচ্ছিল যা ইউনিক্স শেলের সীমাবদ্ধতাগুলো দূর করতে পারে। মেমোরি ব্যবস্থাপনার জটিলতা ও একই কাজের জন্য বারবার কোড লেখার ঝামেলা এড়াতে ডেভেলপাররা সি ব্যবহার করতে চাইত না। তারা পার্ল (Perl) ও টিসিএল (বা টিকল – Tcl) ভাষা দুটি ব্যবহার করত।

পার্ল ও টিসিএল দুটি ভাষাই বেশ চমৎকার ছিল। কিন্তু রোসাম যে প্রজেক্টে কাজ করতেন সেখানে এ দুটি ভাষা ব্যবহার করার সুযোগ ছিল না। রোসাম তাই পাইথন তৈরির উদ্যোগ নিয়েছিলেন। ছোটখাটো কাজের জন্য পার্ল চমৎকার। কিন্তু পার্লের বড় প্রজেক্ট রক্ষণাবেক্ষণ বেশ কষ্টসাধ্য ছিল। অন্যদিকে পাইথনের সিনট্যাক্স অত্যন্ত পরিষ্কার, বেশ গোছানো। তার ওপর ইনডেন্টেশন অত্যাবশ্যক হওয়ায় কোডের পাঠযোগ্যতাও অনেক বেশি। ডেভেলপাররা তাই পার্লের পাশাপাশি, এবং একসময় সম্পূর্ণভাবে পাইথন ব্যবহার শুরু করে।

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

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

Tk, PyQt, PyGTK ইত্যাদি দিয়ে ডেস্কটপ অ্যাপ ডেভেলপমেন্ট বেশ ভালোই চলছে। Kivy দিয়ে কিছু কাজ হলেও মোবাইল অ্যাপের বিশাল বাজারে পাইথনের দখল প্রায় নেই বললেই চলে। এটি পাইথনের একটি বড় সীমাবদ্ধতা। বর্তমানে পাইথনের সবচেয়ে বড় বাজার হচ্ছে ওয়েব প্রোগ্রামিং। তুলনামূলকভাবে অনেক সহজ হওয়ায় শিশুদের প্রোগ্রামিংয়ের সাথে পরিচয় করাতে বেশিরভাগ ক্ষেত্রেই পাইথন ব্যবহার করা হয়। দৈনন্দিন বিভিন্ন বিরক্তিকর কাজ, যেগুলো বারবার করতে হয়, সেগুলো অটোমেট করতে পাইথন ব্যবহার করা হচ্ছে।

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

বর্তমানে পাইথনের ব্যবহার এত ব্যাপক যে, হঠাৎ এর হারিয়ে যাওয়ার বা নতুন কোনো ভাষা দিয়ে প্রতিস্থাপিত হয়ে যাওয়ার কোনো সম্ভাবনা অন্তত নিকট ভবিষ্যতে নেই। তাই যাদের ইচ্ছা আছে, তারা নির্দ্বিধায় পাইথন দিয়ে কাজ করা শুরু করতে পারেন। পাইথনের ভবিষ্যত নিয়ে আপাতত চিন্তা করতে হবে না।

বাংলা ভাষায় পাইথন শেখার জন্য ইন্টারনেটে বেশ কিছু রিসোর্স রয়েছে – 

লেখক – মোশারফ হোসেন।

পাইথন দিয়ে এপিআই ব্যবহার – ৩য় পর্ব

আমরা আবহাওয়ার তথ্য সংগ্রহ ও সংরক্ষণ করার জন্য একটি প্রোগ্রাম মোটামুটি দাঁড় করিয়ে ফেলেছি। প্রোগ্রামটি Open Weather API ব্যবহার করে বর্তমান সময়ের তাপমাত্রা ও আর্দ্রতার তথ্য সংগ্রহ করে। তারপর সেটি ডেটাবেজে সংরক্ষণ করে। আমরা এখানে বেশ কয়েকটি কাজ করছি, কিন্তু সবগুলো কাজ একই জায়গায় করছি। আমাদের উচিত, কাজগুলো আলাদা ফাংশনে করা এবং ফাংশনগুলো এমনভাবে তৈরি করা যেন একটি ফাংশন একটি নির্দিষ্ট কাজ করে।

আমাদের প্রথম কাজটি ছিল ডেটাবেজ টেবিল তৈরি করা। তারপরের কাজ হচ্ছে আবহাওয়ার তথ্য সংগ্রহ করা। সবশেষের কাজ হচ্ছে আবহাওয়ার তথ্য ডেটাবেজে সংরক্ষণ করা। তাহলে আমরা প্রতিটি কাজের জন্য আলাদা ফাংশন তৈরি করতে পারি।

আমি নিচে ফাংশনগুলো দেখিয়ে দিলাম। ফাংশনগুলো পুরোপুরি তৈরি করার দায়িত্ব পাঠকের।

def create_table():
   pass


def get_weather_data():
   pass


def store_weather_data():
   pass


if __name__ == "__main__":
   # create database connection
   conn = sqlite3.connect('example.db')
   c = conn.cursor()

   # create table if it doesn't exist
   create_table()

   # get weather info from open weather map api
   temperature, humidity = get_weather_data()

   # store weather data into database
   store_weather_data(temperature, humidity)

   # close database connection
   conn.close()

ওপরের কোডকে আমরা বলতে পারি মডিউলার (modular) কোড। প্রোগ্রামটি এখন পড়তে ও বুঝতে আগের চেয়ে সহজ। নতুন প্রোগ্রামাররা প্রায়শই মডিউলার কোড লিখতে পারে না, সবকিছু এক জায়গায় লিখে জগাখিচুড়ি পাকিয়ে ফেলে। তাই মডিউলার কোড লেখা বেশ গুরুত্বপূর্ণ।

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

  • আমরা যখন এপিআই কল করছি, সেখানে যদি ইন্টারনেট কানেকশনে কোনো ঝামেলা হয়, কিংবা সার্ভারে কোনো সমস্যা হয়, তখন আমাদের প্রোগ্রাম ক্র্যাশ করবে।
  • আমরা যখন জেসন (json) ডেটা থেকে তাপমাত্রা ও বাতাসের আর্দ্রতা নিচ্ছি, সেখানে ডিকশনারি ব্যবহার করা হচ্ছে। যদি কি (key) না থাকে, তখন প্রোগ্রাম ক্র্যাশ করতে পারে।
  • এসকিউএল কুয়েরি (যেমন, ডেটা ইনসার্ট) ঠিকভাবে না চললে, তখন এরর দিবে এবং সেটিও কোডে ঠিকঠাক হ্যান্ডেল করতে হবে।

পাইথন দিয়ে এপিআই ব্যবহার – ২য় পর্ব

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

আমরা পাইথন প্রোগ্রাম থেকেই temperature নামে একটি টেবিল তৈরি করবো। এই টেবিলের প্রথম কলাম হবে একটি id নামক একটি ইন্টিজার। এটিকে আমরা প্রাইমারি কি, নট নাল এবং অটো-ইনক্রিমেন্ট হিসেবে উল্লেখ করে দিবো। যারা এই কথাটির অর্থ বুঝতে পারে নাই, তাদের চিন্তার কিছু নাই। এই কথার অর্থ না বুঝলেও লেখাটি পড়তে ও প্রোগ্রাম করতে কোনো সমস্যা হবে না। টেবিলে আমরা তাপমাত্রা ও বাতাসের আর্দ্রতা ছাড়াও তারিখ ও সময় সংরক্ষণ করব। 

পাইথন দিয়ে কিভাবে এসকিউলাইট ব্যবহার করতে হয়, সেটি জানা যাবে এখানে – https://docs.python.org/3/library/sqlite3.html। এখন টেবিল তৈরি করার জন্য আমরা এই কোড ব্যবহার করতে পারি –

import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS temperature (id INTEGER PRIMARY KEY AUTOINCREMENT, temp REAL, humidity REAL, datetime TEXT)''')

আর বর্তমান তারিখ ও সময় বের করার জন্য এরকম কোড লিখব –

import datetime
current_time = datetime.datetime.now()

তাহলে আমার পুরো প্রোগ্রামটি দাঁড়াবে এরকম –

import requests
import json
import sqlite3
import datetime

conn = sqlite3.connect('example.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS temperature (id INTEGER PRIMARY KEY AUTOINCREMENT, temp REAL, humidity REAL, datetime TEXT)''')

BASE_URL = "http://api.openweathermap.org/data/2.5/weather"

payload = {"id": "1337179", "APPID": "your api key"}

r = requests.get(BASE_URL, params=payload)
result = r.json()

temperature = result["main"]["temp"]
humidity = result["main"]["humidity"]

current_time = datetime.datetime.now()

c.execute('INSERT INTO temperature (temp, humidity, datetime) VALUES(?, ?, ?)', (temperature, humidity, current_time))

conn.commit()
conn.close()

এখন ওপরের প্রোগ্রামটি রান করলে ডেটাবেজে তাপমাত্রার তথ্য সংরক্ষিত হবে। আমরা টার্মিনাল থেকে বিষয়টি পরীক্ষা করতে পারি। যেই ফোল্ডার বা ডিরেক্টরি থেকে আমরা weather_info.py ফাইলটি রান করেছি, টার্মিনাল থেকে সেখানে গিয়ে আমরা এসকিউলাইট চালু করে তারপর টেবিলের ডেটা দেখতে পারি।

$ sqlite3 example.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> select * from temperature;
1|292.18|56.0|2019-07-29 23:35:32.797251

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

পাইথন দিয়ে এপিআই ব্যবহার – ১ম পর্ব

পৃথিবীতে বিভিন্ন প্রতিষ্ঠান প্রয়োজনীয় অনেক ডেটা সংগ্রহ ও সংরক্ষণ করে। সেই সঙ্গে তারা এপিআই (API)-এর মাধ্যমে সেসব ডেটা যেন অন্যরা পেতে পারে, তার ব্যবস্থাও রাখে। অনেক সময় সেই ডেটা পেতে হলে যেই এপিআই ব্যবহার করতে হয়, সেজন্য মূল্য পরিশোধ করতে হয়, আবার কখনও কখনও বিনামূল্যেও অনেক ডেটা পাওয়া যায়। আবহাওয়া সংক্রান্ত ডেটা, শেয়ার বাজারের ডেটা, মুদ্রার বিনিময় হার, ভৌগলিক বিভিন্ন ডেটা ইত্যাদি অনেক রকমের ডেটাই এপিআই ব্যবহার করে পাওয়া যায়। এখন এই লেখায় আমরা দেখবো, পাইথন প্রোগ্রামে আবহাওয়া সংক্রান্ত এপিআই ব্যবহার করে কিভাবে তথ্য সংগ্রহ ও সংরক্ষণ করতে হয়।

আমরা যদি Weather API লিখে গুগলে সার্চ করি, তাহলে প্রথম পৃষ্ঠাতেই ওপেন ওয়েদার ম্যাপ-এর একটি লিঙ্ক আসবে (https://openweathermap.org/api)। এখানে বিভিন্ন এপিআই আছে, যেখানে বর্তমান সময়ের আবহাওয়ার তথ্য পাওয়া যায়, আবার আবহাওয়ার পূর্বাভাস (forecast) পাওয়ার জন্যও সেখানে এপিআই আছে। আমরা দেখবো বর্তমান সময়ের আবহাওয়ার তথ্য কিভাবে পেতে পারি। সেজন্য আমাদের যেতে হবে Current weather data সেকশনে। এখন, এই এপিআই ব্যবহার করার জন্য একটি এপিআই কি (API Key) প্রয়োজন হবে, আর এই বিষয়ে বিস্তারিত লেখা আছে https://openweathermap.org/appid লিঙ্কে। ওখানে গিয়ে appid (যা আসলে API Key) সেই সম্পর্কে জেনে নিতে হবে। নতুন যেকোনো এপিআই ব্যবহার করার সময় আমাদেরকে ডকুমেন্টেশন পড়ার অভ্যাস তৈরি করতে হবে। অনেক সময় ডকুমেন্টেশন না পড়ে কেবল উদাহরন বা নমুনা কোড দেখলেই বুঝা যায় যে এপিআই কীভাবে ব্যবহার করতে হবে, তবে আমার পরামর্শ হবে, সবসময় ডকুমেন্টেশন পড়ার চেষ্টা করা। তাতে হয়ত ঘণ্টা খানেক বেশি সময় লাগবে, কিন্তু একটা জিনিস ভালোভাবে জানা হয়ে গেলে ব্যবহার করা সহজ হয় এবং অনাকাঙ্খিত অনেক ঝামেলা এড়ানো যায়।

ওপেন ওয়েদার ম্যাপের এপিআই কি পেতে হলে সেখানে সাইন আপ করতে হবে বা একাউন্ট তৈরি করতে হবে। একাউন্ট তৈরি হয়ে গেলে https://home.openweathermap.org/api_keys পেজ থেকে এপিআই কি পাওয়া যাবে এবং প্রয়োজন হলে নতুন এপিআই কি তৈরি করতে হবে।
এখন আমরা চলে যাব, এপিআই-এর ডকুমেন্টেশনে, যেখান থেকে জানা যাবে যে, এপিআই কীভাবে ব্যবহার করতে হবে। ডকুমেন্টেশনের লিঙ্ক হচ্ছে https://openweathermap.org/current। আমরা ঢাকা শহরের জন্য আবহাওয়ার তথ্য জানতে চাইব, আর সেজন্য city id ব্যবহার করতে হবে। ঢাকা শহরের city id জানার জন্য http://bulk.openweathermap.org/sample/ ওয়েবপেজ থেকে city.list.josn ফাইলটি ডাউনোড করে dhaka লিখে সেই ফাইলে সার্চ করতে হবে। তো আমি এভাবে জানতে পারলাম যে, ঢাকার city id হচ্ছে 1337179. তাহলে ওয়েব ব্রাউজারে আমরা যদি http://api.openweathermap.org/data/2.5/weather?id=1337179&APPID=xyz ঠিকানায় যাই, তাহলে আমরা ঢাকা শহরের আবহাওয়ার তথ্য দেখতে পাবো। xyz-এর জায়গায় এপিআই কি বসাতে হবে। এখন, এই তথ্য আমরা পাইথন প্রোগ্রামের সাহায্যে পাওয়ার ব্যবস্থা করবো। এজন্য আমরা requests মডিউল ব্যবহার করবো। এই মডিউল সম্পর্কে উদাহরণসহ আলোচনা করেছি “পাইথন দিয়ে প্রোগ্রামিং শেখা দ্বিতীয় খণ্ড” বইতে।

import requests

URL = "http://api.openweathermap.org/data/2.5/weather"
payload = {"id": "1337179", "APPID": "7dd241yyyycd16xxxx"}

r = requests.get(URL, params=payload)

print(r.text)

প্রোগ্রামটি রান করলে নিচের মতো একটি আউটপুট পাবো –

{"coord":{"lon":90.42,"lat":24.17},"weather":[{"id":721,"main":"Haze","description":"haze","icon":"50n"}],"base":"stations","main":{"temp":300.15,"pressure":1001,"humidity":88,"temp_min":300.15,"temp_max":300.15},"visibility":3500,"wind":{"speed":3.6,"deg":90},"clouds":{"all":75},"dt":1564268448,"sys":{"type":1,"id":9145,"message":0.0091,"country":"BD","sunrise":1564269901,"sunset":1564317863},"timezone":21600,"id":1337179,"name":"Dhaka Division","cod":200}

এখন আমরা এই আউটপুট কপি করে https://jsonformatter.org/json-pretty-print ওয়েবসাইটে বসিয়ে সুন্দর করে দেখতে পারি। অথবা পাইথন প্রোগ্রামটি একটু পরিবর্তন করেও দেখা যায়। আগের কোডে নিচের দুটি লাইন যুক্ত করতে হবে – 

result = r.json()
print(json.dumps(result, indent=4))

আর প্রোগ্রামের শুরুতে json মডিউল ইমপোর্ট করতে হবে। এখন প্রোগ্রাম রান করলে সুন্দরভাবে আউটপুট দেখা যাবে। 

আমাদের দরকার আজকের দিনের বর্তমান তাপমাত্রা, যেটি আমরা পাব result[“main”][“temp”]-এ। আর সেই সঙ্গে বাতাসের আর্দ্রতার তথ্যও আমরা নেব, আর সেটি পাব result[“main”][“humidity”]-তে। এখন তাপমাত্রা আমরা কোন এককে পাচ্ছি? এটি ডকুমেন্টেশন পড়লেই বুঝা যাবে (এখানে – https://openweathermap.org/current#current_JSON)। 

আমাদের প্রোগ্রামটি এখন দাঁড়াচ্ছে এমন – 

import requests
import json

BASE_URL = "http://api.openweathermap.org/data/2.5/weather"

payload = {"id": "1337179", "APPID": "7dd241yyyycd16xxxx"}

r = requests.get(BASE_URL, params=payload)
result = r.json()

print("Temperature", result["main"]["temp"])
print("Humidity", result["main"]["humidity"])

পরের লেখায় আমরা দেখবো, কিভাবে এই তথ্য আমরা একটি ডেটাবেজে সংরক্ষণ করতে পারি।

নোট – ওপরের প্রোগ্রামগুলোতে 7dd241yyyycd16xxxx এর বদলে নিজের একাউন্ট থেকে সঠিক APP ID বসাতে হবে।

পাইথন দিয়ে সর্টিং – ২য় পর্ব

পাইথন প্রোগ্রামিং ভাষায় সর্ট করার পদ্ধতি।

আগের পর্বে আমরা দেখেছি কীভাবে পাইথনের বিল্টইন ফাংশন ব্যবহার করে সর্টিং করা যায়। এই লেখায় আমরা আরেকটু জটিল সর্টিংয়ের কাজ করব, তবে বিল্টইন ফাংশন ব্যবহার করেই কাজগুলো করা হবে।

ধরা যাক, একটি লিস্টে বিভিন্ন ফলের নাম এবং সেই ফল কতগুলো করে আছে, সেটি দেওয়া আছে – fruits = [(‘orange’, 3), (‘apple’, 3), (‘banana’, 2), (‘mango’, 10), (‘guava’, 5)]

এখন এই লিস্টকে আমরা যদি সর্ট করি, তাহলে ফলের নাম অনুসারে সর্ট হয়ে যাবে –

>>> fruits = [('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
>>> print(sorted(fruits))
[('apple', 3), ('banana', 2), ('guava', 5), ('mango', 10), ('orange', 3)]

ফলের নাম অনুসারে সর্ট হওয়ার কারণ কী? ফলের সংখ্যা অনুসারেও তো সর্ট হতে পারত। এখানে প্রতিটি টাপলের প্রথম উপাদান সেই টাপলের প্রতিনিধিত্ব করে। যেমন, টাপলে আমরা যদি আগে সংখ্যা লিখতাম, তারপরে ফলের নাম লিখতাম, তাহলে সংখ্যা অনুযায়ী সর্ট হতো।

কিন্তু আমরা যদি চাই, আমাদেরকে যেই লিস্ট দেওয়া আছে সেটি ফলের নাম নয়, বরং সংখ্যা অনুসারে সর্ট করা হবে, তখন কী করতে হবে? প্রতিটি টাপলের দ্বিতীয় উপাদানটি যদি সেই টাপলের প্রতিনিধিত্ব করত, তাহলে কিন্তু আমরা কাঙ্ক্ষিত উপায়ে সর্ট করতে পারতাম। sorted() ফাংশনে key নামে একটি প্যারামিটার আছে, যার মাধ্যমে আমরা বলে দিতে পারি, কোন উপাদানটির ওপর ভিত্তি করে সর্ট করার কাজটি হবে। key-তে আসলে একটি ফাংশন দেওয়া হয়, আর যেই লিস্ট সর্ট করতে হবে, তার প্রতিটি উপাদান সেই ফাংশনের মধ্যে পাঠানো হয়। ফাংশনটি একটি উপাদান রিটার্ন করবে, যার ওপর ভিত্তি করে সর্টিং হবে। তাহলে আমরা এখানে যেই কাজটি করতে চাচ্ছি, সেখানে এমন একটি ফাংশন লিখতে হবে, যা (‘apple’, 3) ইনপুট নিবে আর 3 রিটার্ন করবে।

def compare_fnc(item):
    return item[1]

fruits = [('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
print(sorted(fruits, key=compare_fnc))

ওপরের কোড রান করলে দেখা যাবে ফলের সংখ্যা অনুযায়ী ছোট থেকে বড় ক্রমে সর্ট করা হয়ে গিয়েছে।

[('banana', 2), ('orange', 3), ('apple', 3), ('guava', 5), ('mango', 10)]

বড় থেকে ছোট ক্রমে সর্ট করতে চাইলে লিখতে হবে sorted(fruits, key=compare_fnc, reverse=True).

পাইথনে operator মডিউলে একটি ফাংশন আছে itemgetter, যেটি ব্যবহার করে আমরা ওপরের কাজটি আরো সহজে করতে পারি, আমাদের নিজেদের কষ্ট করে ফাংশন তৈরি করতে হবে না।

from operator import itemgetter

fruits = [('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
print(sorted(fruits, key=itemgetter(1)))

ওপরের কোডে itemgetter(1) এর বদলে itemgetter(0) লিখলে ফলের নাম অনুযায়ী সর্ট হয়ে যাবে। এখন আমরা যদি চাই, প্রথমে ফলের সংখ্যা অনুযায়ী সর্ট হবে, তারপরে যেসব ফলের সংখ্যা সমান, তাদের মধ্যে নাম অনুযায়ী সর্ট হবে, তাহলে কী করতে হবে? মানে আমাদের আউটপুট (‘orange’, 3′), (‘apple’, 3) ক্রমে না এসে (‘apple’, 3), (‘orange’, 3) ক্রমে আসবে। কাজটি সহজেই করা যায় এভাবে –

>>> fruits = [('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
>>> print(sorted(fruits, key=itemgetter(1, 0)))
[('banana', 2), ('apple', 3), ('orange', 3), ('guava', 5), ('mango', 10)]

এখান আমরা itemgetter(1, 0) ব্যবহার করেছি। কিন্তু এখন আমরা যদি চাই, ফলের সংখ্যার বড় থেকে ছোট ক্রমে সর্ট হবে আর যেসব ফলের সংখ্যা সমান, তারা নাম অনুযায়ী ছোট থেকে বড় ক্রমে সর্ট হবে, তখন কী করতে হবে? তাহলে দুইবার সর্ট করার কাজটি করতে হবে –

>>> fruits = [('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
>>> print(fruits)
[('orange', 3), ('apple', 3), ('banana', 2), ('mango', 10), ('guava', 5)]
>>> fruits = sorted(fruits, key=itemgetter(0))
>>> print(fruits)
[('apple', 3), ('banana', 2), ('guava', 5), ('mango', 10), ('orange', 3)]
>>> fruits = sorted(fruits, key=itemgetter(1), reverse=True)
>>> print(fruits)
[('mango', 10), ('guava', 5), ('apple', 3), ('orange', 3), ('banana', 2)]

ওপরের পদ্ধতি কাজ করে, কারণ পাইথনের sorted() ফাংশন stable সর্ট করে। sort()-এর ক্ষেত্রেও একই কথা প্রযোজ্য।

পাইথন দিয়ে সর্টিং – ১ম পর্ব

এই টিউটোরিয়ালে পাইথন দিয়ে কিভাবে সর্ট করতে হয়, সেটি আলোচনা করা হবে। প্রোগ্রামিংয়ে সর্ট (sort) করা মানে হচ্ছে কোনো নির্দিষ্ট ক্রমে সাজানো। পাইথনে কোনো লিস্টকে সর্ট করার জন্য একটি মেথড দেওয়া আছে, যার নাম হচ্ছে sort()। নিচের কোড দেখলেই sort() কী করে, সেটি বুঝা যাবে –

>>> li = [1, 3, 4, 5, 6, 2, 3]
>>> li.sort()
>>> print(li)
[1, 2, 3, 3, 4, 5, 6]

প্রোগ্রামটি রান করলে দেখা যাচ্ছ যে, লিস্টের সংখ্যাগুলো ছোট থেকে বড় ক্রমে সাজানো হয়ে গিয়েছে। এখন, কেউ যদি চায় যে, সে বড় থেকে ছোট ক্রমে সাজাবে, তাহলে sort() মেথডের ভেতরে reverse নামে একটি প্যারামিটার আছে, সেখানে True পাঠাতে হবে –

>>> li = [1, 3, 4, 5, 6, 2, 3]
>>> li.sort(reverse=True)
>>> print(li)
[6, 5, 4, 3, 3, 2, 1]

একটি স্ট্রিংয়ের লিস্টকেও একইভাবে সর্ট করা যায়। যেমন –

>>> countries = ["Bangladesh", "Japan", "Australia", "Canada", "Singapore"]
>>> countries.sort()
>>> print(countries)
['Australia', 'Bangladesh', 'Canada', 'Japan', 'Singapore']

আমরা দেখতে পাচ্ছি, লিস্টকে সর্ট করা হলে লিস্টের ভেতরের উপাদানগুলো নির্দিষ্ট ক্রমে সাজানো হয়ে যায়, আগের লিস্টটি আর পাওয়া যায় না। কিন্তু আমরা যদি সেটি পেতে চাই, তাহলে কী করতে হবে? পাইথনে আরেকটি ফাংশন আছে, যার নাম sorted(). এটি সর্ট করার পরে একটি নতুন লিস্ট রিটার্ন করে। যেই লিস্টটি সর্ট করা হচ্ছে, সেটি পরিবর্তন হয় না। নিচের কোড দেখলেই এটি বুঝতে পারা যাবে –

>>> li = [1, 3, 4, 5, 6, 2, 3]
>>> nums = sorted(li)
>>> print(nums)
[1, 2, 3, 3, 4, 5, 6]
>>> print(li)
[1, 3, 4, 5, 6, 2, 3]

sorted() ফাংশনটি কেবল লিস্ট না, অন্য ইটারেবলের (iterable) ওপরও কাজ করে। যেমন, আমরা চাইলে একটি টাপলকে সর্ট করতে পারি। ফলাফল হিসেবে একটি লিস্ট রিটার্ন করা হবে।

>>> tpl = (3, 8, 1, 4, 6, 2)
>>> result = sorted(tpl)
>>> result
[1, 2, 3, 4, 6, 8]
>>> tpl
(3, 8, 1, 4, 6, 2)

sorted() ফাংশনেও উল্টো ক্রমে সর্ট করতে চাইলে reverse প্যারামিটার ব্যবহার করা যাবে।

>>> li = [1, 3, 4, 5, 6, 2, 3]
>>> nums = sorted(li, reverse=True)
>>> print(nums)
[6, 5, 4, 3, 3, 2, 1]
>>> print(li)
[1, 3, 4, 5, 6, 2, 3]

পাইথনের এই বিল্টইন সর্ট করার ফাংশনটিতে আসলে Timsort নামক একটি অ্যালগরিদম ব্যবহার করা হয়।

পাইথনের সর্টিং নিয়ে পরবর্তী লেখায় আমরা আরেকটু জটিল ডেটা স্ট্রাকচার কীভাবে সর্ট করতে হয়, সেটি দেখব।

একটি লিস্টে দ্বিতীয় লিস্টের সকল উপাদানের উপস্থিতি – প্রোগ্রামিং ইন্টারভিউ সমস্যা ১৫

সহজ প্রোগ্রামিং ইন্টারভিউ সমস্যা।

সমস্যা – একটি ফাংশন লিখতে হবে, যেখানে দুটি লিস্ট ইনপুট দেওয়া হবে। প্রথম লিস্টে যদি দ্বিতীয় লিস্টের সকল উপাদান থাকে তাহলে True রিটার্ন করতে হবে, আর নইলে False রিটার্ন করতে হবে।

সমাধান – সমাধান খুবই সহজ। দ্বিতীয় লিস্টের প্রতিটি উপাদান প্রথম লিস্টে আছে কী না, সেটি পরীক্ষা করতে হবে। যদি না থাকে, তাহলে False রিটার্ন করতে হবে, আর যদি সব উপাদানই প্রথম লিস্টে পাওয়া যায়, তাহলে True রিটার্ন করতে হবে।

def is_sublist(listA, listB):
    for item in listB:
        if item not in listA:
            return False
    return True

এখন প্রশ্ন হচ্ছে, ওপরের কোডের কমপ্লেক্সিটি কত? অতিরিক্ত কোনো মেমোরি ব্যবহার করা হচ্ছে না, তাই স্পেস কমপ্লেক্সিটি হচ্ছে O(1)। আর টাইম কমপ্লেক্সিটি হচ্ছে O(n * m), যেখানে n হচ্ছে listA-এর উপাদান সংখ্যা আর m হচ্ছে listB-এর উপাদান সংখ্যা। অনেকেই এখানে ভুল করে টাইম কমপ্লেক্সিটি বলবে O(n), কিন্তু item not in listA – এখানে কিন্তু লিস্টের সকল উপাদান পরীক্ষা করতে হতে পারে, তাই শুধু এই কাজটির টাইম কমপ্লেক্সিটি হচ্ছে O(m)।

পরবর্তী প্রশ্ন হচ্ছে, ওপরের কোডটি কীভাবে আরো ইফিশিয়েন্ট করা যায়? এজন্য সেট (set) ব্যবহার করা যেতে পারে। প্রথমে listA-কে সেটে রূপান্তর করতে হবে। তারপরে কোড আগের মতোই। আমি আর এখানে কোড লিখে দেখালাম না, এটি নিজে লিখতে হবে।

লিস্টে যদি n সংখ্যক উপাদান থাকে, তাহলে এটিকে সেটে রূপান্তর করার কমপ্লেক্সিটি হচ্ছে O(n)। আর তারপরে যেই হোড হবে, সেটি ঠিকঠাকমতো লিখলে তার কমপ্লেক্সিটি হবে O(m)। কারণ একটি উপাদান সেটে আছে কী না, সেটি পরীক্ষা করার জন্য O(1) সময় লাগে। তাহলে প্রোগ্রামটির টাইম কমপ্লেক্সিটি হবে O(n) + O(m)। তবে সেট ব্যবহার করায় কিন্তু এই প্রোগ্রামের স্পেস কমপ্লেক্সিটি বেড়ে যাচ্ছে, স্পেস কমপ্লেক্সিটি কত সেটি পাঠকের জন্য কুইজ (কমেন্টে উত্তর দেওয়া যাবে)।

দুটি বিষয় লক্ষ রাখতে হবে। ইন্টারভিউতে স্পেস কমপ্লেক্সিটি না জিজ্ঞাসা করলেও বলা উচিত। মানে কমপ্লেক্সিটি জিজ্ঞাসা করলে টাইম ও স্পেস কমপ্লেক্সিটি দুটোই বলা উচিত। আর দ্বিতীয়ত, ফাংশন লেখার পরে তার জন্য ইউনিট টেস্ট লিখতে পারলে ভালো হয়, এতে ইন্টারভিউয়ারকে একটু খুশি করা যায় আর কী।

সকল সাবসেট তৈরি – প্রোগ্রামিং ইন্টারভিউ সমস্যা ১৪

সমস্যাঃ একটি সেট দেওয়া আছে, সেই সেটের সকল সাবসেট তৈরি করার ফাংশন লিখতে হবে।

সমাধানঃ ইন্টারভিউতে এই প্রশ্ন করা হলে শুরুতেই দুটি বিষয় পরিষ্কার হয়ে নিতে হবে। সেটি হচ্ছে, ফাঁকা সেট এবং ওই সেটটি নিজে তার সাবসেট কী না। আমাদের এই আলোচনায়, দুটি উত্তরই হচ্ছে, হ্যাঁ।

সমাধান দেখার আগে নিজে চেষ্টা করা উচিত। এখানে গিয়ে সমস্যা দেখা যাবে ও সমাধান জমা দেওয়া যাবে – https://leetcode.com/problems/subsets/

তাহলে, ইনপুট যদি হয় [1, 2, 3], আউটপুট হবে, [[], [1], [2], [3], [1, 2], [2, 3], [1, 3], [1, 2, 3]]। আউটপুট লিস্টের উপাদানগুলোর ক্রম ভিন্ন হলেও সমস্যা নেই, কিন্তু একই জিনিস দুইবার থাকতে পারবে না।

আমরা রিকার্শন ব্যবহার করে খুব সহজেই সমস্যাটির সমাধান করতে পারি। আমরা প্রতিবার সেট থেকে একটি উপাদান নেওয়ার চেষ্টা করব। তবে আমাদেরকে খেয়াল রাখতে হবে যেন, একই উপাদান একাধিকবার নেওয়া না হয়। সেজন্য একটি বুলিয়ান অ্যারে বা লিস্ট ব্যবহার করতে পারি (visited)। বিস্তারিত ব্যাখ্যা না করে, বরং কোড লিখে দিচ্ছি। তবে কোড বুঝার জন্য খাতা-কলম নিয়ে বসতে হবে। আর যারা ডিএফএস (dfs)-এর সঙ্গে পরিচিত, তারা সহজেই বুঝতে পারবে। আর যারা পরিচিত নও, তাদেরও খুব একটা সমস্যা হবে না।

def subsets1(S):
    if S == []:
        return [[]]
    
    result = [[]]
    n = len(S)
    visited = [False] * n
    
    def recurse(i, n, li):
        if i == n:
            return
        
        if len(li) > 0:
            result.append([x for x in li])
        
        for j in range(i, n):
            if visited[j]:
                continue
            visited[j] = True
            li.append(S[j])
            recurse(j, n, li)
            li.pop()
            visited[j] = False
            
    recurse(0, n, [])
    return result

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

সম্পূর্ণ কোড এখানে – https://gist.github.com/tamim/87d3b79ff15d3375a98e9e0cd73b7c73

 

LCS-Zero – প্রোগ্রামিং ইন্টারভিউ সমস্যা ১২

সমস্যাঃ একটা ইন্টিজারের অ্যারে দেওয়া আছে। সেখানে যদি পরপর কতগুলো সংখ্যা পাওয়া যায়, যাদের সমষ্টি শূন্য, সেই সংখ্যাগুলোর মধ্যে সবচেয়ে বেশিসংখ্যক ক্রমিক (অ্যারেতে ক্রমানুসারে সাজানো) সংখ্যাগুলো বের করতে হবে।

উদাহরণঃ 1, 2, -2, 4, -4 – এই সংখ্যাগুলোর মধ্যে, 2, -2 -এর যোগফল 0; 4, -4 – এর যোগফল 0; আবার 2, -2, 4, -4 সংখ্যাগুলোর যোগফলও 0। এখন সবচেয়ে বেশি সংখ্যক ক্রমিক সংখ্যা হচ্ছে 2, -2, 4, -4। তাই আমাদের উত্তর হবে 2, -2, 4, -4.

সমস্যাটি কেউ নিজে সমাধান করতে চাইলে এখানে চেষ্টা করতে হবে – https://www.interviewbit.com/problems/largest-continuous-sequence-zero-sum/

সমাধানঃ আমরা প্রথমে সবচেয়ে সহজ বুদ্ধি প্রয়োগ করতে পারি। অ্যারেতে যদি n সংখ্যক উপাদান থাকে, তাহলে সবগুলো উপাদানের সমষ্টি 0 কী না, সেটি পরীক্ষা করি। তারপরে n-1 সংখ্যক ক্রমিক সংখ্যার সমষ্টি 0 কী না পরীক্ষা করি। তারপর n-2 সংখ্যক ক্রমিক সংখ্যার সমষ্টি পরীক্ষা করি… এভাবে যতক্ষণ না আমরা সমষ্টি 0 পাচ্ছি, ততক্ষণ পরীক্ষা করবো আর n-এর মান এক কমাতে থাকবো 1 পর্যন্ত। যেমন, আমাদের যদি 1, 2, 3, -4, 5 – এই পাঁচটি সংখ্যা দেওয়া হয়, তাহলে প্রথমে পরীক্ষা করবো –

1 + 2 + 3 + -4 + 5 = 7

তারপরে চারটি করে ক্রমিক সংখ্যা নেব –
1 + 2 + 3 + -4 = 2
2 + 3 + -4 + 5 = 6

এবারে তিনটি করে ক্রমিক সংখ্যা –
1 + 2 + 3 = 6
2 + 3 + -4 = 1
3 + -4 + 5 = 4

এখন দুটি করে ক্রমিক সংখ্যা নেই –
1 + 2 = 3
2 + 3 = 5
3 + -4 = -1
-4 + 5 = 1

এখন একটি করে সংখ্যা নিয়ে দেখবো তাদের সমষ্টি (অর্থাৎ সেই সংখ্যাটির মান) 0 কী না। এই উদাহরণে এরকম সংখ্যা নাই।

যাই হোক, আশা করি, আমি কী করতে চাচ্ছি, তা বুঝাতে পেরেছি। এখন নিজে কোড লেখার চেষ্টা করতে হবে।

আমরা এরকম কোড লিখতে পারি –

def lszero1(A):
    n = len(A)
    
    for window_size in range(n, 0, -1):
        for start in range(0, n):
            if start+window_size > n:
                    break
            if 0 == sum(A[start:start+window_size]):
                return A[start:start+window_size]
                
    return []

এই কোডের কমপ্লেক্সিটি কত? sum() ফাংশনের কমপ্লেক্সিটি হচ্ছে O(n)। তাহলে আমাদের ফাংশনের কমপ্লেক্সিটি হবে O(n^3). প্রতিবার কিন্তু আসলে sum() ফাংশন ব্যবহার না করলেও চলে। আমরা যদি জানি, 1 + 2 + 3 = 6, তাহলে 2 + 3 + 4 হবে, আগের যোগফল থেকে 1 বিয়োগ ও 4 যোগ। বিষয়টি একটু ঠান্ডা মাথায় চিন্তা করলেই বুঝে ফেলার কথা। এই কাজটি ঠিকভাবে করতে পারলে আমরা আমাদের কোডের কমপ্লেক্সিটি O(n^2)-এ নামিয়ে আনতে পারবো।

for window_size in range(n, 0, -1):
    w_sum = sum(A[0:window_size])
    if w_sum == 0:
        return A[0:window_size]
    for start in range(1, n):
        if start + window_size > n:
            break    
        w_sum = w_sum - A[start-1] + A[start+window_size-1]
        if w_sum == 0:
            return A[start:start+window_size]                

এখন, আরো গভীরভাবে চিন্তা করলে, এই সমস্যাটির সমাধান O(n) কমপ্লেক্সিটিতেও করা সম্ভব। এবং 90% ক্ষেত্রে ইন্টারভিউয়ার হয়ত সেটিই আশা করবেন, কিংবা বলে দিবেন যে O(n) কমপ্লেক্সিটিতে সমাধান করতে। সেটি নিজে করার চেষ্টা করতে হবে। আমি কেবল একট হিন্ট দিয়ে দিচ্ছি –

A = [1, 2, -2, 4, -4], এর শুরু থেকে ক্রমিক সংখ্যাগুলোর যোগফল 1, 3 (1+2), 1 (1+2+-2), 5 , (1+2+-2+4), 1 (1+2+-2+4+-4)। এগুলো একটি অ্যারেতে রাখি –
S = [1, 3, 1, 5, 1]. এখন এই ক্ষেত্রে, প্রথম সংখ্যাটি 1, আবার পঞ্চম সংখ্যাটিও 1। অর্থাৎ প্রথম সংখ্যার পরে পরপর চারটি সংখ্যা যোগ করে যোগফলের কোনো পরিবর্তন হলো না। এতে আমরা কী বুঝলাম?

১->০, ০->১ – প্রোগ্রামিং ইন্টারভিউ সমস্যা ৮

সমস্যাঃ সম্প্রতি আমি একটা ইন্টারভিউতে এই সমস্যাটি দেখেছি – একটা ফাংশন লিখতে হবে, যেখানে ইনপুট 0 হলে আউটপুট হবে 1 আর ইনপুট 1 হলে আউটপুট হবে 0। ফাংশনটা বিভিন্নভাবে লিখতে হবে। ফাংশনের ইনপুট কেবল 0 আর 1 হবে, অন্য কোনো সংখ্যা নয়।

সমাধানঃ আমার সমাধান দেখার আগে নিজে নিজে চেষ্টা করা উচিত।

এটা আসলে ঠিক কতভাবে করা যায়, আমার জানা নেই। তবুও পাইথন ব্যবহার করে আমি বেশ কয়েকভাবে ফাংশনটি লিখতে পারি।

প্রথমে অবশ্যই if-else ব্যবহার করে –

def fnc1(n):
    if n == 1:
        return 0
    else:
        return 1

ওপরের প্রোগ্রামটা পাইথনে আরেকটু সুন্দরভাবে লেখা যায় –

def fnc2(n):
    return 0 if n == 1 else 1

এবারে কিছু গাণিতিক বুদ্ধিশুদ্ধি ব্যবহার করি –

def fnc3(n):
    return (n + 1) % 2

এবারে লিস্ট ডেটা স্ট্রাকচার ব্যবহার করি –

def fnc4(n):
    li = [1, 0]
    return li[n]

একইভাবে চাইলে টাপলও ব্যবহার করা যায়। ডিকশনারি ব্যবহার করেও করা যায় –

def fnc5(n):
    dt = {1: 0, 0: 1}
    return dt[n]

এবারে বিট লেভেলে চিন্তা করা যাক।  আমরা যদি 1 এর সঙ্গে 0-কে এক্সর (XOR) করি, তাহলে 1 পাবো, আর 1-কে এক্সর করলে 0 পাবো –

def fnc6(n):
    return 1 ^ n

আমার মাথায় এগুলোই এসেছে। আর কোনোভাবে ফাংশনটি লেখা যায়?