2025, Oct 31 13:01
Python में मैट्रिक्स को in-place ट्रांसपोज़ करने के सही तरीके
Python में मैट्रिक्स का in-place ट्रांसपोज़ करें: mutate बनाम rebind समझें, grid.clear या slice असाइनमेंट से सूची बदलें, और zip(*data) से संक्षिप्त समाधान—बिना import.
Python में किसी मैट्रिक्स को “in place” ट्रांसपोज़ करना अक्सर उलझा देता है। मूल बात यह है कि फ़ंक्शन के अंदर किसी लोकल वेरिएबल को दोबारा बाँधना (rebind) कॉलर के ऑब्जेक्ट को नहीं बदलता, जबकि ऑब्जेक्ट को बदलना (mutate) बदल देता है। अगर आप ट्रांसपोज़ की हुई एक कॉपी बनाकर उसे लोकल पैरामीटर नाम को असाइन कर देते हैं, तो फ़ंक्शन के बाहर वाली मूल मैट्रिक्स जस की तस रहती है। नीचे इस समस्या का चरणबद्ध विवरण और बिना किसी इम्पोर्ट के in-place ट्रांसपोज़ करने के कुछ साफ़ तरीके दिए गए हैं।
समस्या का सेटअप
हमें मैट्रिक्स को इस तरह ट्रांसपोज़ करना है कि मूल वेरिएबल बदल जाए। नीचे दिया प्रयास फ़ंक्शन के अंदर अपेक्षित मैट्रिक्स प्रिंट करता है, लेकिन फ़ंक्शन के बाहर मैट्रिक्स मूल रूप में ही रहती है।
def flip_grid(grid: list):
    alt = []
    for i in range(len(grid)):
        row = []
        for j in range(len(grid)):
            row.append(grid[j][i])
        alt.append(row)
    grid = []
    for i in range(len(alt)):
        row = []
        for j in range(len(alt)):
            row.append(alt[i][j])
        grid.append(row)
    print(grid)  # फ़ंक्शन के अंदर
board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flip_grid(board)
print(board)     # फ़ंक्शन के बाहर
क्या हो रहा है और क्यों
जिस नाम को आप फ़ंक्शन में पास करते हैं, वह लोकल पैरामीटर से बंध जाता है। फ़ंक्शन के भीतर grid = [] असाइन करना मूल सूची (list) को नहीं बदलता; यह सिर्फ़ लोकल नाम grid को नई, खाली सूची से बाँध देता है। कॉलर के पास पुरानी सूची ही रहती है। मूल मैट्रिक्स बदलने के लिए आपको लोकल वेरिएबल को पुनः असाइन करने के बजाय वही सूची ऑब्जेक्ट बदलना होगा जो कॉलर ने पास किया है।
न्यूनतम बदलाव वाला समाधान
उसी सूची ऑब्जेक्ट को सच में संशोधित करने के लिए उसे साफ़ करें या स्लाइस-असाइनमेंट का उपयोग करें, और फिर उसे भरें। यानी लोकल रीबाइंडिंग की जगह परिवर्तनकारी (mutating) ऑपरेशन करें।
def flip_grid(grid: list):
    alt = []
    for i in range(len(grid)):
        row = []
        for j in range(len(grid)):
            row.append(grid[j][i])
        alt.append(row)
    # पुनः-बाइंड करने के बजाय परिवर्तित (mutate) करें
    grid.clear()          # या: grid[:] = []
    for i in range(len(alt)):
        row = []
        for j in range(len(alt)):
            row.append(alt[i][j])
        grid.append(row)
board = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flip_grid(board)
print(board)
इससे कॉलर के संदर्भित सूची ऑब्जेक्ट की पहचान बनी रहती है और उसकी सामग्री ट्रांसपोज़ किए गए डेटा से अपडेट हो जाती है।
एक संक्षिप्त इन-प्लेस तरीका
आप अस्थायी कॉपी से बच सकते हैं: ट्रांसपोज़ सीधे गणना करें और स्लाइस-असाइनमेंट के जरिए सामग्री बदल दें। यहाँ दो संक्षिप्त रूप हैं।
def transpose_in_place(data: list):
    data[:] = [
        [row[col_idx] for row in data]
        for col_idx in range(len(data[0]))
    ]
एक और संक्षिप्त विकल्प वही असर देता है:
def transpose_in_place(data: list):
    data[:] = [list(col) for col in zip(*data)]
यह क्यों मायने रखता है
Python में किसी नाम को दोबारा बाँधने और किसी ऑब्जेक्ट को बदलने के फर्क को समझना बुनियादी है। यही फर्क तय करता है कि आप API कैसे डिज़ाइन करते हैं, साइड इफ़ेक्ट्स के बारे में कैसे सोचते हैं, और उन फ़ंक्शंस को कैसे डीबग करते हैं जो अपने इनपुट को बदलने का इरादा रखते हैं। अगर आपका लक्ष्य कॉलर के डेटा को अपडेट करना है, तो ऑब्जेक्ट को वहीं बदलें; अगर आपका लक्ष्य नया मान निकालना है, तो उसे रिटर्न करें और कॉलर को अपना वेरिएबल रीबाइंड करने दें। कुछ संदर्भों में किसी समर्पित लाइब्रेरी का उपयोग बेहतर बैठता है, लेकिन सीखने के लिए इम्पोर्ट से बच रहे हों, तो ऊपर दिखाए गए in-place तरीके साफ़ और प्रभावी हैं।
निष्कर्ष
किसी फ़ंक्शन के भीतर से मूल मैट्रिक्स को बदलने के लिए पैरामीटर नाम को दोबारा असाइन न करें। इसके बजाय, आधारभूत सूची को बदलें—जैसे उसे साफ़ करके या स्लाइस-असाइनमेंट से—और फिर ट्रांसपोज़ की गई पंक्तियाँ भर दें। यदि आप फ़ंक्शनल तरीका पसंद करते हैं, तो नई मैट्रिक्स रिटर्न करें और कॉल साइट पर उसे रीबाइंड करें। किसी भी तरह, परिवर्तन (mutation) बनाम असाइनमेंट के बारे में स्पष्ट रहना आपकी मैट्रिक्स से जुड़ी क्रियाओं को अनुमानित और सही रखेगा।