ट्रैक
/
Python
Python
/
अभ्यास
/
रेल इंजन चालक
रेल इंजन चालक

रेल इंजन चालक

सीखने का अभ्यास

परिचय

अनपैकिंग का मतलब है किसी कलेक्शन, जैसे list, tuple या dict, के एलिमेंट्स को इटरेशन के ज़रिए निकालना। इस तरह निकाली गई वैल्यू को फिर उसी स्टेटमेंट में वेरिएबलो को असाइन किया जा सकता है। इसे ही आम तौर पर मल्टीपल असाइनमेंट कहा जाता है।

खास ऑपरेटर * और ** अक्सर अनपैकिंग और मल्टीपल असाइनमेंट में इस्तेमाल होते हैं।

Caution

*<variable_name> और **<variable_name> को * और ** से भ्रमित नहीं करना चाहिए। * और ** का उपयोग क्रमशः गुणा और घात के लिए होता है, जबकि *<variable_name> और **<variable_name> पैकिंग और अनपैकिंग ऑपरेटर के रूप में उपयोग होते हैं।

मल्टीपल असाइनमेंट

मल्टीपल असाइनमेंट में असाइनमेंट ऑपरेटर (=) के बाईं ओर वेरिएबलो की संख्या और दाईं ओर वैल्यू की संख्या बराबर होनी चाहिए। वैल्यू को अलग करने के लिए कॉमा , का इस्तेमाल कीजिए:

>>> a, b = 1, 2
>>> a
1

अगर मल्टीपल असाइनमेंट में दी गई वैल्यू के लिए वेरिएबलो की संख्या गलत हो, तो ValueError मिलती है:

>>> x, y, z = 1, 2

ValueError: too many values to unpack (expected 3, got 2)

मल्टीपल असाइनमेंट सिर्फ एक डेटा टाइप तक सीमित नहीं है:

>>> x, y, z = 1, "Hello", True
>>> x
1

>>> y
'Hello'

>>> z
True

मल्टीपल असाइनमेंट का इस्तेमाल lists के एलिमेंट्स को आपस में बदलने के लिए किया जा सकता है। यह तरीका सॉर्टिंग एल्गोरिदम में काफी आम है। उदाहरण के लिए:

>>> numbers = [1, 2]
>>> numbers[0], numbers[1] = numbers[1], numbers[0]
>>> numbers
[2, 1]

चूँकि tuples इम्यूटेबल होते हैं, आप tuple के एलिमेंट्स को आपस में नहीं बदल सकते।

अनपैकिंग

Note

नीचे दिए गए उदाहरणों में lists का इस्तेमाल हुआ है, लेकिन यही कॉन्सेप्ट tuples पर भी लागू होते हैं।

Python में list/tuple/dictionary के एलिमेंट्स को अलग-अलग वेरिएबलो में अनपैक करना संभव है। चूँकि lists/tuples में वैल्यू एक तय क्रम में होती हैं, इसलिए उन्हें उसी क्रम में वेरिएबलो में अनपैक किया जाता है:

>>> fruits = ["apple", "banana", "cherry"]
>>> x, y, z = fruits
>>> x
"apple"

अगर कुछ वैल्यू की ज़रूरत नहीं है, तो आप उन्हें चिह्नित करने के लिए _ का इस्तेमाल कर सकते हैं:

>>> fruits = ["apple", "banana", "cherry"]
>>> _, _, z = fruits
>>> z
"cherry"

गहरी अनपैकिंग

किसी list या tuple के अंदर बंद list/tuple (जिसे नेस्टेड ऐरे/ट्यूपल भी कहते हैं) से वैल्यू अनपैक करके असाइन करना उसी तरह काम करता है जैसे सतही अनपैकिंग करता है, लेकिन संदर्भ या स्थिति स्पष्ट करने के लिए अक्सर क्वालिफायर की ज़रूरत पड़ती है:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [c, d]] = fruits_vegetables
>>> a
"apple"

>>> d
"potato"

आप नेस्टेड list/tuple के सिर्फ एक हिस्से को भी गहराई से अनपैक कर सकते हैं:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [a, [c, d]] = fruits_vegetables
>>> a
["apple", "banana"]

>>> c
"carrot"

अगर अनपैकिंग में वेरिएबलो की जगह गलत हो या वैल्यू की संख्या गलत हो, तो आपको ValueError मिलती है:

>>> fruits_vegetables = [["apple", "banana"], ["carrot", "potato"]]
>>> [[a, b], [d]] = fruits_vegetables

ValueError: too many values to unpack (expected 1)

* की मदद से ऐरे/ट्यूपल अनपैक करना

list/tuple को अनपैक करते समय आप "बची हुई" वैल्यू को पकड़ने के लिए * ऑपरेटर का इस्तेमाल कर सकते हैं। यह list/tuple को स्लाइस करने से ज़्यादा स्पष्ट है (जो कुछ स्थितियों में कम पठनीय होता है)। उदाहरण के लिए, पहला एलिमेंट निकाला जा सकता है और फिर बाकी वैल्यू को पहले एलिमेंट के बिना एक नए list में रखा जा सकता है:

>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *last = fruits
>>> x
"apple"

>>> last
["banana", "cherry", "orange", "kiwi", "melon", "mango"]

हम list के शुरू और अंत की वैल्यू भी निकाल सकते हैं और बीच की सारी वैल्यू को एक साथ समूहित कर सकते हैं:

>>> fruits = ["apple", "banana", "cherry", "orange", "kiwi", "melon", "mango"]
>>> x, *middle, y, z = fruits
>>> y
"melon"

>>> middle
["banana", "cherry", "orange", "kiwi"]

हम गहरी अनपैकिंग में * का भी इस्तेमाल कर सकते हैं:

>>> fruits_vegetables = [["apple", "banana", "melon"], ["carrot", "potato", "tomato"]]
>>> [[a, *rest], b] = fruits_vegetables
>>> a
"apple"

>>> rest
["banana", "melon"]

डिक्शनरी अनपैक करना

डिक्शनरी को अनपैक करना list/tuple को अनपैक करने से थोड़ा अलग है। डिक्शनरी पर इटरेशन डिफ़ॉल्ट रूप से कीज़ पर होता है। इसलिए जब आप dict को अनपैक करते हैं, तो आप सिर्फ कीज़ अनपैक कर सकते हैं, वैल्यू नहीं:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory
>>> x
"apple"

अगर आप वैल्यू को अनपैक करना चाहते हैं, तो <dict>.values() मेथड का इस्तेमाल कर सकते हैं:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.values()
>>> x
6

अगर कीज़ और वैल्यू दोनों की ज़रूरत हो, तो <dict>.items() मेथड का इस्तेमाल कीजिए। <dict>.items() की-वैल्यू जोड़ों वाला एक इटरेबल व्यू बनाता है। इन्हें एक tuple में अनपैक किया जा सकता है:

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> x, y, z = fruits_inventory.items()
>>> x
("apple", 6)

पैकिंग

पैकिंग का मतलब है कई वैल्यू को एक list में समूहित करके उसे किसी वेरिएबल को असाइन करना। यह तब काम आता है जब आप वैल्यू को अनपैक करना, उनमें बदलाव करना और फिर नतीजों को वापस पैक करके किसी वेरिएबल में रखना चाहते हैं। इससे 2 या अधिक lists/tuples/dicts को आपस में जोड़ना भी संभव हो जाता है।

* की मदद से ऐरे/ट्यूपल पैक करना

list/tuple को पैक करने के लिए * ऑपरेटर का इस्तेमाल किया जा सकता है। यह सारी वैल्यू को एक list/tuple में पैक कर देता है।

>>> fruits = ("apple", "banana", "cherry")
>>> more_fruits = ["orange", "kiwi", "melon", "mango"]

# fruits and more_fruits are unpacked and then their elements are packed into combined_fruits
>>> combined_fruits = *fruits, *more_fruits

# If there is no * on to the left of the "=" the result is a tuple
>>> combined_fruits
("apple", "banana", "cherry", "orange", "kiwi", "melon", "mango")

# If the * operator is used on the left side of "=" the result is a list.
# Note the trailing comma.
>>> *combined_fruits_too, = *fruits, *more_fruits
>>> combined_fruits_too
['apple', 'banana', 'cherry', 'orange', 'kiwi', 'melon', 'mango']

* को बाईं ओर इस्तेमाल करने के बारे में ज़्यादा जानकारी के लिए PEP 3132 देखिए।

** की मदद से डिक्शनरी पैक करना

डिक्शनरी को पैक करने के लिए ** ऑपरेटर का इस्तेमाल किया जाता है। यह एक डिक्शनरी के सारे की-वैल्यू जोड़ों को दूसरी डिक्शनरी में पैक कर देता है, या दो डिक्शनरी को आपस में जोड़ देता है।

>>> fruits_inventory = {"apple": 6, "banana": 2, "cherry": 3}
>>> more_fruits_inventory = {"orange": 4, "kiwi": 1, "melon": 2, "mango": 3}

# fruits_inventory and more_fruits_inventory are unpacked into key-values pairs and combined.
>>> combined_fruits_inventory = {**fruits_inventory, **more_fruits_inventory}

# then the pairs are packed into combined_fruits_inventory
>>> combined_fruits_inventory
{"apple": 6, "banana": 2, "cherry": 3, "orange": 4, "kiwi": 1, "melon": 2, "mango": 3}

फंक्शन के साथ * और ** का उपयोग

फंक्शन पैरामीटर के साथ पैकिंग

जब आप ऐसा फंक्शन बनाते हैं जो किसी भी संख्या में आर्गुमेंट स्वीकार करता है, तो फंक्शन बनाते समय आप *args या **kwargs का इस्तेमाल कर सकते हैं। *args का इस्तेमाल किसी भी संख्या के पोज़िशनल (गैर-कीवर्ड) आर्गुमेंट को एक tuple के रूप में पैक करने के लिए होता है और **kwargs का इस्तेमाल किसी भी संख्या के कीवर्ड आर्गुमेंट को एक डिक्शनरी के रूप में पैक करने के लिए होता है।

*args का उपयोग:

# This function is defined to take any number of positional arguments

>>> def my_function(*args):
...     print(args)

# Arguments given to the function are packed into a tuple

>>> my_function(1, 2, 3)
(1, 2, 3)

>>> my_function("Hello")
("Hello")

>>> my_function(1, 2, 3, "Hello", "Mars")
(1, 2, 3, "Hello", "Mars")

**kwargs का उपयोग:

# This function is defined to take any number of keyword arguments

>>> def my_function(**kwargs):
...   print(kwargs)

# Arguments given to the function are packed into a dictionary

>>> my_function(a=1, b=2, c=3)
{"a": 1, "b": 2, "c": 3}

*args और **kwargs का इस्तेमाल एक साथ भी किया जा सकता है:

>>> def my_function(*args, **kwargs):
...   print(sum(args))
...   for key, value in kwargs.items():
...       print(str(key) + " = " + str(value))

>>> my_function(1, 2, 3, a=1, b=2, c=3)
6
a = 1
b = 2
c = 3

आप खास पोज़िशनल आर्गुमेंट की अनुमति देने के लिए *args से पहले पैरामीटर भी लिख सकते हैं। तब अलग-अलग कीवर्ड आर्गुमेंट **kwargs से पहले आने चाहिए।

Caution

आर्गुमेंट को व्यवस्थित करना ज़रूरी है इस तरह:

def my_function(<positional_args>, *args, <key-word_args>, **kwargs)

अगर आप इस क्रम का पालन नहीं करते, तो आपको एरर मिलती है।

>>> def my_function(a, b, *args):
...   print(a)
...   print(b)
...   print(args)

>>> my_function(1, 2, 3, 4, 5)
1
2
(3, 4, 5)

आर्गुमेंट को गलत क्रम में लिखने पर एरर मिलती है:

>>>def my_function(*args, a, b):
... print(args)

>>>my_function(1, 2, 3, 4, 5)
Traceback (most recent call last):
  File "c:\something.py", line 3, in <module>
    my_function(1, 2, 3, 4, 5)
TypeError: my_function() missing 2 required keyword-only arguments: 'a' and 'b'

फंक्शन कॉल में अनपैकिंग

आप आर्गुमेंट के list/tuple को फंक्शन कॉल में अनपैक करने के लिए * का इस्तेमाल कर सकते हैं। यह उन फंक्शनों के लिए बहुत काम का है जो iterable नहीं लेते:

>>> def my_function(a, b, c):
...   print(c)
...   print(b)
...   print(a)

numbers = [1, 2, 3]
>>> my_function(*numbers)
3
2
1

zip() बिल्ट-इन के साथ * अनपैकिंग का इस्तेमाल भी एक आम उदाहरण है। zip() फंक्शन कई इटरेबल लेता है और हर iterable की वैल्यू को समूहित करके tuples की एक list लौटाता है:

>>> values = (['x', 'y', 'z'], [1, 2, 3], [True, False, True])
>>> a, *rest = zip(*values)
>>> rest
[('y', 2, False), ('z', 3, True)]

निर्देश

आपके दोस्त Linus एक लोकोमोटिव इंजीनियर हैं, जो शहरों के बीच मालगाड़ियाँ चलाते हैं। ट्रेनें संभालने में वे बहुत माहिर हैं, लेकिन लॉजिस्टिक्स या कंप्यूटर के मामले में उतने अच्छे नहीं हैं। वे चाहते हैं कि आप प्रोग्रामिंग की अपनी समझ से ट्रेनों की जानकारी व्यवस्थित करने और रूट डेटा की गलतियाँ सुधारने में उनकी मदद करें।

Note

यह अभ्यास स्लाइसिंग, इंडेक्सिंग और dict के अलग-अलग मेथड से आसानी से हल किया जा सकता है। लेकिन हम चाहते हैं कि नीचे दिए गए हर काम को हल करते समय आप पैकिंग, अनपैकिंग और मल्टीपल असाइनमेंट का अभ्यास करें।

1. सभी वैगनों का ऐरे बनाइए

आपके दोस्त हर वैगन के पहचानकर्ता (ID) का हिसाब रखते आ रहे हैं, लेकिन उन्हें कभी पक्का पता नहीं होता कि किसी भी समय सिस्टम को कितने वैगन संसाधित करने पड़ेंगे। अगर यह डेटा एक ही list में पैक कर दिया जाए, तो लॉजिस्टिक्स प्रोग्राम के बाकी हिस्सों के लिए काम बहुत आसान हो जाएगा।

एक फंक्शन get_list_of_wagons() बनाइए, जो किसी भी संख्या में वैगन ID लेता है। हर ID एक धनात्मक पूर्णांक होगी। फिर फंक्शन को दी गई सारी ID एक ही list के रूप में return करनी चाहिए।

>>> get_list_of_wagons(1, 7, 12, 3, 14, 8, 5)
[1, 7, 12, 3, 14, 8, 5]

2. वैगनों का ऐरे ठीक कीजिए

अब तक आपको इस डेटा का और लॉजिस्टिक्स प्रोग्राम में इसके इस्तेमाल का थोड़ा अंदाज़ा हो गया होगा। ID सिस्टम हमेशा लोकोमोटिव को ID 1 देता है, और ट्रेन के बाकी सारे वैगनों को 1 से बड़ी कोई बेतरतीब ID देता है।

आपके दोस्त को ट्रेन से दो नए वैगन जोड़ने थे और वे सिस्टम अपडेट करना भूल गए! अब ट्रेन के list में पहले दो वैगनों को अंत में ले जाना होगा, वरना सारा क्रम बिगड़ जाएगा।

इसे और उलझाने के लिए, आपके दोस्त को अभी एक दूसरा list मिला है, जिसमें लगता है कि कुछ छूटी हुई वैगन ID हैं। उन्हें बस इतना याद है कि नए वैगनों को हटाने के बाद, इस दूसरे list की ID को तय किए गए लोकोमोटिव के ठीक बाद रखा जाना चाहिए।

Linus उनकी गलतियाँ सुधारने और डेटा को एक जगह इकट्ठा करने के लिए आपके बहुत आभारी रहेंगे।

एक फंक्शन fix_list_of_wagons() बनाइए, जो वैगन ID वाले दो lists लेता है। इसे पहले list के पहले दो आइटम अंत में ले जाने चाहिए, और दूसरे list की वैल्यू को लोकोमोटिव ID (1) के पीछे (यानी उसके दाईं ओर) डालना चाहिए। फिर फंक्शन को बदलावों के साथ एक list return करना चाहिए।

>>> fix_list_of_wagons([2, 5, 1, 7, 4, 12, 6, 3, 13], [3, 17, 6, 15])
[1, 3, 17, 6, 15, 7, 4, 12, 6, 3, 13, 2, 5]

3. छूटे हुए ठहराव जोड़िए

अब जब सारा वैगन डेटा सही है, तो Linus चाहेंगे कि आप सिस्टम की रूटिंग जानकारी अपडेट करें। एक परिवहन मार्ग पर ट्रेन सामान लेने या छोड़ने के लिए कुछ अलग-अलग स्टेशनों पर रुक सकती है। हर यात्रा में इन बीच वाले ठहरावों की संख्या अलग हो सकती है। आपके दोस्त चाहते हैं कि आप सिस्टम की रूटिंग dict में छूटी हुई या अतिरिक्त डिलीवरी जानकारी जोड़कर उसे अपडेट करें।

एक फंक्शन add_missing_stops() बनाइए, जो एक रूटिंग dict और उसके बाद किसी भी संख्या में कीवर्ड आर्गुमेंट लेता है। ये आर्गुमेंट एक या अधिक ठहराव रखने वाले dict के रूप में हो सकते हैं, या stop_number=city जैसे किसी भी संख्या में कीवर्ड जोड़ों के रूप में। फिर आपके फंक्शन को रूटिंग dict में एक अतिरिक्त key जोड़कर लौटाना चाहिए, जिसमें जोड़े गए सारे ठहराव क्रम से रखी एक list हो।

>>> add_missing_stops({"from": "New York", "to": "Miami"},
                      stop_1="Washington, DC", stop_2="Charlotte", stop_3="Atlanta",
                      stop_4="Jacksonville", stop_5="Orlando")

{"from": "New York", "to": "Miami", "stops": ["Washington, DC", "Charlotte", "Atlanta", "Jacksonville", "Orlando"]}

4. रूटिंग जानकारी का विस्तार कीजिए

Linus रूटिंग प्रोग्राम पर काम कर रहे हैं और उन्होंने देखा है कि कुछ रूट में कुछ ज़रूरी जानकारी गायब है। शुरुआती रूट जानकारी एक dict के रूप में बनाई गई है, और आपके दोस्त चाहते हैं कि आप उस dict को वह सब जोड़कर अपडेट करें जो छूट गया हो। सिस्टम के हर रूट को थोड़ी अलग जानकारी चाहिए, इसलिए Linus एक सामान्य हल पसंद करेंगे।

extend_route_information() नाम का एक फंक्शन बनाइए, जो दो dicts लेता है। पहले dict में वे दो शहर होते हैं जहाँ से और जहाँ तक ट्रेन का रूट चलता है।

दूसरे dict में ट्रेन की गति, लंबाई या तापमान जैसी रूटिंग की बाकी जानकारी होती है। फंक्शन को सारी रूटिंग जानकारी वाला एक जोड़ा हुआ dict लौटाना चाहिए।

Note

दूसरे dict में उदाहरण में दिखाई गई प्रॉपर्टी से अलग या उससे अधिक प्रॉपर्टी हो सकती हैं।

>>> extend_route_information({"from": "Berlin", "to": "Hamburg"}, {"length": "100", "speed": "50"})
{"from": "Berlin", "to": "Hamburg", "length": "100", "speed": "50"}

5. वैगन डिपो ठीक कीजिए

जब Linus ने वैगन डिपो देखा, तो उन्हें पता चला कि वैगन सही क्रम में नहीं रखे जा रहे थे। ID के अलावा हर वैगन का एक रंग भी होता है, जो उसमें लदे सामान के प्रकार के हिसाब से तय होता है। डिपो में वैगन ग्रिड में रखे जाते हैं, जहाँ ग्रिड के हर कॉलम में एक ही रंग के वैगन होते हैं।

लेकिन लॉजिस्टिक्स सिस्टम ऐसी lists दिखाता है जिनमें डिपो में रखे जाने वाले वैगनों की पंक्तियाँ रंग के हिसाब से समूहित होती हैं। ग्रिड के सही तरीके से काम करने के लिए ज़रूरी है कि हर पंक्ति में तीन अलग-अलग रंग हों, ताकि कॉलम रंग के हिसाब से एक-दूसरे से मिल सकें। आपके दोस्त चाहते हैं कि आप वैगन डिपो की lists ठीक करें, जिससे वैगन सही तरीके से रखे जा सकें।

fix_wagon_depot() नाम का एक फंक्शन बनाइए, जो तीन आइटम वाली एक list लेता है। list का हर आइटम एक सबलिस्ट (या "पंक्ति") होता है, जिसमें तीन tuples होते हैं। हर tuple एक (<wagon ID>, <wagon color>) जोड़ा होता है।

आपके फंक्शन को तीन "पंक्ति" lists वाली एक list लौटाना चाहिए, जिसमें वैगनों को उनकी सही जगहों पर आपस में बदलकर क्रम ठीक किया गया हो।

>>> fix_wagon_depot([
                    [(2, "red"), (4, "red"), (8, "red")],
                    [(5, "blue"), (9, "blue"), (13,"blue")],
                    [(3, "orange"), (7, "orange"), (11, "orange")],
                    ])

[
[(2, "red"), (5, "blue"), (3, "orange")],
[(4, "red"), (9, "blue"), (7, "orange")],
[(8, "red"), (13,"blue"), (11, "orange")]
]
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Python Exercism

रेल इंजन चालक शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और Python को 17 कॉन्सेप्ट146 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।