Συζήτηση
Γεια χαρά, Επισκέπτης
Όνομα χρήστη: Κωδικός: Να με θυμάσαι

ΘΕΜΑ: αντιγραφή list

αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1101

  • ektoras
  • Το Άβαταρ του/της ektoras
  • Αποσυνδεμένος
  • p_____
  • Δημοσιεύσεις: 6
πως μπορω να αντιγραψω τα στοιχεια μιας λιστας Α σε μια αλλη λιστα Β???(χωρις να αλλαζουν τα στοιχεια της Β οταν αλλαξουν τα στοιχεια τησ Α)

Κωδικας:

A = [ ]
B = [ ]
 
for i in range(2):
 
  A.append( [ ] )
  B.append( [ ] )
 
A = [ [ 1 , 2 ] , [ 3 , 6 ] ]
 
B = list( A )
 
A[ 0 ][ 0 ] = B[ 0 ][ 0 ] * 2
 
print( A )
print( B )

γιατι αλλαζει και η λιστα Β?
Τελευταία διόρθωση: 13 Χρόνια 2 Μήνες πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1102

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Η συμπεριφορά που παρατηρείς έχει να κάνει με αυτό που γενικότερα ονομάζεται call by refernence και call by value, καθώς και με τα mutable και immutable objects (για την ακρίβεια στην python τα calls είναι by object). Δε θα προσπαθήσω να το εξηγήσω με τεχνικούς όρους γιατί στάνταρ θα πω κοτσάνα (o myle είναι ο άνθρωπος για αυτά :P).

Mε απλά λόγια η python δημιουργεί μία καινούρια λίστα κάθε φορά που πληκτρολογείς τις αγκύλες. Αν δεν τις πληκτρολογήσεις δε δημιουργείται καινούρια λίστα. Απλά δημιουργείται ένα αντικείμενο που "δείχνει" στο αρχικό. Αν ξέρεις C/C++ σκέψου το σαν ένα pointer. Αν όχι ξέχασε το.

Για να αντιγράψεις μια λίστα δες τις τελευταίες 2 γραμμές του κώδικα που ακολουθεί. Αν πας να αλλάξεις τα στοιχεία των λίστων "d" και "e", θα δεις ότι η a θα μείνει ως έχει.
a = [1, 2, 3, 4]  # Create a list
b = []            # Create another list
 
c = a             # No list is created here. c justs "points" to a
 
c[0] = 0          # Changing the first item of both a and c lists
 
d = list(a)       # Creating a new list. d is a copy of a
e = a[:]          # Creating another list. e is a copy of a too.

ένας εύκολος τρόπος για να δεις αν μια λίστα είναι αντίγραφο μιας άλλης ή απλά "δειχνει" στην ίδια λίστα είναι να χρησιμοποιήσεις τη συνάρτηση id(). Τρέξε το παρακάτω και θα δεις ότι το αποτέλεσμα της id είναι το ίδιο για τις 2 πρώτες κλήσεις τις id αλλά διαφορετικό για την τρίτη.

a = [2,2,2]   # create a list
b = a         # b "points" to a
c = list(a)   # c is a copy of a
 
id(a)
id(b)
id(c)

Διάβασε και ΑΥΤΟ.
Τελευταία διόρθωση: 13 Χρόνια 1 Εβδομάδα πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1103

  • ektoras
  • Το Άβαταρ του/της ektoras
  • Αποσυνδεμένος
  • p_____
  • Δημοσιεύσεις: 6
pmav πραγματικα βλεπεις να κανω κατι διαφορετικο???
ολα αυτα που εγραψες περι αναφορας κ αξιας τα εχω κατανοησει ηδη...

αλλα με λιστες 2Χ2 δεν φαινεται να λειτουργει συμφωνα με τον κωδικα που εχω παραθεσει πιο πανω...
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1104

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Εσύ έχεις δίκιο πολύ, αλλά εχω και εγώ λίγο γιατί δεν ήξερα...

Κοίταξε τι έκανα εγώ χτες:
>>> a = [[1,2],[3,4]]
>>> b = [[7,8],[9,0]]
>>> id(a[0][0]) == id(b[0][0])   # Check if a[0][0] "points" to b[0][0]
False                            # It doesn't
 
>>> a[0][0] = b[0][0]            
>>> id(a[0][0]) == id(b[0][0])   # Check if a[0][0] "points" to b[0][0]
True                             # It does
 
>>> a
[[7, 2], [3, 4]]
>>> b
[[7, 8], [9, 0]]
 
>>> a[0][0] = b[0][0] * 2
>>> id(a[0][0]) == id(b[0][0])
False
 
>>> a
[[14, 2], [3, 4]]
>>> b
[[7, 8], [9, 0]]
όπως βλέπεις η τιμή της "b" δεν άλλαξε.

Η διαφορά με αυτό που έκανες εσύ ήταν ότι δεν αντέγραψα τη λίστα "a" με τη "list()" αλλά δημιούργησα μια καινούρια. Κοίτα ποια είναι η διαφορά:
>>> a = [[1,2],[3,4]]
>>> b = list(a)
>>> id(a) == id(b)
False                     # As expected! But...
>>> id(a[0][0]) == id(b[0][0])
True                      # Each element of b "points" at the same object as a!!!
Κάτι μάθαμε και σήμερα...

Λογικά στην αντιγραφή με list, η σειρα είναι η εξής:
1. Υπολογίζεται το δεξί τμήμα της εκχώρησης τιμής "b[0][0] * 2"
2. Εκχωρείται στο αριστερό, δηλαδή στο "a[0][0]"
3. To "b[0][0]" επειδή δείχνει στο ίδιο αντικείμενο με το "a[0][0]", δείχνει και αυτό τη νέα τιμή.

Αν κάποιος το καταλαβαίνει καλύτερα ας μας το εξηγήσει.
Τελευταία διόρθωση: 13 Χρόνια 2 Μήνες πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1105

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Τώρα στο ερώτημα για το πως μπορείς να αντιγράψεις μια λίστα χωρίς να έχεις προβλήματα, ένας τρόπος είναι με loops ή με list comprehension:
a = [1, 2, 3]
b = []
b.append([i for i in a])
 
id(a[0]) == id(b[0])         # Should evaluate to False
Τελευταία διόρθωση: 13 Χρόνια 2 Μήνες πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1107

  • myle
  • Το Άβαταρ του/της myle
  • Αποσυνδεμένος
  • Admin
  • Δημοσιεύσεις: 467
  • Ληφθείσες Ευχαριστίες 15
Η πιο απλή λύση είναι deep copy.
«Αν υποθέσουμε ότι αυτό είναι δυνατό, (να μεταδώσουμε τη σοφία παντού) τότε ειλικρινά ο τρόπος ζωής των θεών θα περάσει στους ανθρώπους. Τα πάντα θα είναι γεμάτα...
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 2 Μήνες πριν #1124

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Μία πραγματικά εξαιρετική επεξήγηση του τρόπου με τον οποίο πρέπει να σκεφτόμαστε σαν python-istas. Νομίζω ότι πρέπει να διαβαστεί από όλους!
Τελευταία διόρθωση: 13 Χρόνια 2 Μήνες πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.

Απ: αντιγραφή list 13 Χρόνια 1 Εβδομάδα πριν #1357

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Η επιθυμητή συμπεριφορά για πίνακες 2 διαστάσεων με χρήση list-comprehensions.
# "Wrong" behavior
inner = [0] * 10
outer = [inner] * 5
outer[0][2] = 1
print outer
 
# "Right behavior
outer = [[0] * 10 for i in range(5)]
outer[0][2] = 1
print outer
Το σωστό και το λάθος εντός εισαγωγικών, καθώς ίσως υπάρχουν περιπτώσεις που η επιθυμητή συμπεριφορά να είναι η "wrong"

Η deepcopy που ανέφερε ο myle είναι ο ευκολότερος τρόπος, αρκεί τα δεδομένα της λίστας να είναι αριθμοί, strings ή κάτι παρόμοιο. Αν είναι περίπλοκα αντικείμενα (κλάσεις, instances κτλ) τότε υπάρχει το ενδεχόμενο να δημιουργηθούν περίεργα bugs.
Τελευταία διόρθωση: 13 Χρόνια 1 Εβδομάδα πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.
Συντονιστές: pmav99
Χρόνος δημιουργίας σελίδας: 0.621 δευτερόλεπτα

Μοιράσου το!

Powered by CoalaWeb

Λίστα Ταχυδρομείου