Vi segnalo una curiosità in cui mi sono appena imbattuto e che potrebbe
essere utile sapere.
Iniziamo da questo assegnamento apparentemente innocuo.
2.1.0 :047 > data = [ [] ] * 4
=> [[], [], [], []]
2.1.0 :048 > data[0]
=> []
2.1.0 :052 > data.class
=> Array
2.1.0 :053 > data[0].class
=> Array
Tutto in ordine.
2.1.0 :055 > data[0] << “a”
=> [“a”]
2.1.0 :056 > data
=> [[“a”], [“a”], [“a”], [“a”]]
Ops! Inspettato, vero?
Il problema è solo con i []
2.1.0 :057 > data = [[“a”],[“b”],[“c”],[“d”]]
=> [[“a”], [“b”], [“c”], [“d”]]
2.1.0 :058 > data[0] << “a”
=> [“a”, “a”]
2.1.0 :059 > data
=> [[“a”, “a”], [“b”], [“c”], [“d”]]
Proviamo un’altra via:
2.1.0 :060 > data = [ [] ] * 4
=> [[], [], [], []]
2.1.0 :062 > data[0] = data[0] + [“a”]
=> [“a”]
2.1.0 :063 > data
=> [[“a”], [], [], []]
2.1.0 :064 > data[0] += [“a”]
=> [“a”, “a”]
2.1.0 :065 > data
=> [[“a”, “a”], [], [], []]
Ma la ragione qual è? Nicola R. a cui l’ho mostrato poco fa ha avuto
l’intuizione giusta. Gli [] in data sono lo stesso oggetto:
2.1.0 :067 > seeding_groups[0].object_id # questo è [“a”, “a”]
=> 37696480
2.1.0 :068 > seeding_groups[1].object_id # questi sono i []
=> 37990580
2.1.0 :069 > seeding_groups[2].object_id
=> 37990580
2.1.0 :070 > seeding_groups[3].object_id
=> 37990580
Non lasciatevi ingannare dagli 80 finali, leggete bene tutto il numero.
I quattro [] con cui ho inizializzato data sono in realtà lo stesso
oggetto e assegnare ad uno assegna a tutti.
Invece il metodo + crea un nuovo oggetto.
2.1.0 :071 > x = []
=> []
2.1.0 :072 > x.object_id
=> 37389760 # non è quello di prima, non tutti gli [] sono uguali
2.1.0 :073 > a = [“a”]
=> [“a”]
2.1.0 :074 > a.object_id
=> 37309980
2.1.0 :075 > x += a
=> [“a”]
2.1.0 :076 > x.object_id
=> 37247380
Il colpevole è l’operatore *
2.1.0 :077 > y = [ [“a”] ] * 4
=> [[“a”], [“a”], [“a”], [“a”]]
2.1.0 :078 > y[0].object_id
=> 37037460
2.1.0 :079 > y[1].object_id
=> 37037460
Giustamente non sa come clonare un oggetto generico e sceglie
l’implementazione banale, un po’ inutile a dire il vero.
Il modo corretto per creare il mio array sarebbe stato questo:
2.1.0 :080 > z = Array.new(4) { [] }
=> [[], [], [], []]
2.1.0 :081 > z[0].object_id
=> 36888280
2.1.0 :082 > z[1].object_id
=> 36888240
Ma anche data = [ [], [], [], [] ] sarebbe andato bene!