Bir dizinin tam bir kopyasını nasıl yaparım?


100

Bir dizinin tam olarak kopyasını nasıl yapabilirim?

Swift'de bir dizinin kopyalanması hakkında bilgi bulmakta zorlanıyorum.

Kullanmayı denedim .copy()

var originalArray = [1, 2, 3, 4]
var duplicateArray = originalArray.copy()

5
neden doğrudan böyle bir değer var duplicateArray = originalArray
atamıyorsunuz

1
Bu benim durumumda çalışmıyor. Bu, aynı diziye yalnızca bir başvuru olan başka bir nesne oluşturur ve sonunda aynı diziye başvuran 2 değişken elde edersiniz.
user1060500

Yanıtlar:


176

Diziler, Swift'de tam değerli semantiğe sahiptir, bu nedenle süslü hiçbir şeye gerek yoktur.

var duplicateArray = originalArray tüm ihtiyacın olan.


Dizinizin içeriği bir başvuru türü ise, evet, bu yalnızca işaretçileri nesnelerinize kopyalar. İçeriğin derin bir kopyasını gerçekleştirmek için, bunun yerine mapher bir örneği kullanır ve bir kopyasını gerçekleştirirsiniz. NSCopyingProtokole uyan Temel sınıfları için şu copy()yöntemi kullanabilirsiniz :

let x = [NSMutableArray(), NSMutableArray(), NSMutableArray()]
let y = x
let z = x.map { $0.copy() }

x[0] === y[0]   // true
x[0] === z[0]   // false

Burada Swift'in değer semantiğinin sizi korumaya çalıştığı tuzaklar olduğuna dikkat edin - örneğin, NSArraydeğişmez bir diziyi temsil ettiğinden , copyyöntemi yalnızca kendisine bir referans döndürür, böylece yukarıdaki test beklenmedik sonuçlar verir.


Bunu oyun alanında bu basit kodla denedim var x = [UIView(), UIView(), UIView()] var y = x for i in x { NSLog("%p", i) } println("---") for i in y { NSLog("%p", i) }ve şu çıktıyı aldım: 0x7fa82b0009e0 0x7fa82b012660 0x7fa82b012770 ---0x7fa82b0009e0 0x7fa82b012660 0x7fa82b012770 Kopyalanmış gibi görünmüyor, nedenini biliyor musunuz?
Phil Niedertscheider

@PNGamingPower: x adresleri içerir. y bu adreslerin kopyalarını içerir. X [0] 'ı değiştirirseniz, y [0] değişmez. (x [0] = x [1] deneyin, y [0] değişmeyecek). Bu nedenle, y, x'in derin bir kopyasıdır, ancak yalnızca işaretçileri kopyaladınız, işaret ettikleri şeyi değil.
ragnarius

@ragnarius, yani temelde "kopya" nın ne anlama geldiğini tanımlamalıyız, ya işaretçiyi ya da değeri kopyalayarak. Bu nedenle, işaretçiler dizisini kopyalamak / çoğaltmak için çözüm budur, ancak değerler dizisini nasıl çoğaltabilirsiniz? Amaç x[0] == x[1]ama x[0] === y[0]başarısız olmalı
Phil Niedertscheider

Array'in değer semantiği dizinin "kopyasını" gereksiz kıldığından, bu kabul edilen yanıt olmalıdır.
Scott Ahten

Bu benim için çalışmıyor. Bu yöntemi takip edersem, aynı nesne dizisine işaret eden iki referans alırım. Listeden bir öğeyi kaldırırsam, liste kopyalanmadığı için her iki nesne referansına da yansıtılır, bunun yerine nesneye sadece referans verilmiştir.
user1060500

28

Nate haklı. İlkel dizilerle çalışıyorsanız tek yapmanız gereken duplicateArray öğesini originalArray öğesine atamaktır.

Eksiksizlik adına, bir NSArray nesnesi üzerinde çalışıyor olsaydınız, NSArray'in tam bir kopyasını yapmak için aşağıdakileri yaparsınız:

var originalArray = [1, 2, 3, 4] as NSArray

var duplicateArray = NSArray(array:originalArray, copyItems: true)

Bu harika! Teşekkür ederim!
Patrick

23

Nate'in cevabı için üçüncü bir seçenek var:

let z = x.map { $0 }  // different array with same objects

* DÜZENLENMİŞ * düzenleme burada başlar

Yukarıdakiler esasen aşağıdaki ile aynıdır ve aşağıdaki eşitlik operatörünü kullanmak daha iyi sonuç verecektir çünkü dizi değiştirilmedikçe kopyalanmayacaktır (bu tasarım gereğidir).

let z = x

Daha fazlasını buradan okuyun: https://developer.apple.com/swift/blog/?id=10

* DÜZENLENMİŞ * düzenleme burada biter

bu diziye eklemek veya çıkarmak orijinal diziyi etkilemez. Bununla birlikte, nesnelerin herhangi birinin dizinin tuttuğu özelliklerin değiştirilmesi orijinal dizide görülür. Çünkü dizideki nesneler kopya değildir (dizinin ilkel sayıları değil, nesneleri tuttuğunu varsayarak).


Etkisi var, test ettim. iki dizi var, eğer 1'de değişiklik yaparsanız, ikincisi etkilenir
Filthy Knight

1
Hayır, dizi nesneler yerine ilkel türleri tutmadığı sürece olmaz. O zaman cevapta belirtildiği gibi etkiliyor. Basit bir test vakası:var array1: [String] = ["john", "alan", "kristen"]; print(array1); var array2 = array1.map { $0 }; print(array2); array2[0] = "james"; print(array1); print(array2);
oyalhi

1
Lütfen özel bir sınıf kullanarak daha iyi bir örnek için oluşturduğum şu ana bakın: gist.github.com/oyalhi/3b9a415cf20b5b54bb3833817db059ce
oyalhi

Sınıfınız destekliyorsa NSCopying, bir diziyi çoğaltın:let z = x.map { $0.copy as! ClassX }
John Pang

Swift'in BufferPointer'larını kullanıyorsanız, doğrudan bir kopya olarak kullanmanız gereken sürüm budur. Orijinal veya kopyalanan dizideki bir değeri değiştirmeden önce, Swift orijinalin değerlerini kopyaya kopyalayacak ve sonra devam edecektir. Bunun yerine İşaretçileri kullanırsanız, Swift, değişiklikler olduğunda veya olduğunda şimdi kullanılmayacaktır, bu nedenle potansiyel olarak her iki diziyi de değiştirebilirsiniz.
Justin Ganzer

16

Normal nesneler için yapılabilecek, kopyalamayı destekleyen bir protokol uygulamak ve nesne sınıfının bu protokolü şu şekilde uygulamasını sağlamaktır:

protocol Copying {
    init(original: Self)
}

extension Copying {
    func copy() -> Self {
        return Self.init(original: self)
    }
}

Ve sonra klonlama için Array uzantısı:

extension Array where Element: Copying {
    func clone() -> Array {
        var copiedArray = Array<Element>()
        for element in self {
            copiedArray.append(element.copy())
        }
        return copiedArray
    }
}

ve bu hemen hemen, kodu görüntülemek ve bir örneği kontrol etmek için bu özü


Bu çok zaman kazandırdı, teşekkürler.
Abhijit

Alt sınıflar için protokol, gereksinim init'in alt sınıfın türüyle uygulandığını garanti edemez. Sizin için kopyalamayı uygulayan bir kopyalama protokolü bildiriyorsunuz, ancak yine de clone () uyguluyorsunuz, bu mantıklı değil.
Binarian

1
@iGodric kopya, koleksiyondaki öğeler içindir ve klon, tüm koleksiyon için geçerlidir; öğeleri için kopya uygulandığında kullanılabilir. Mantıklı olmak? Ayrıca derleyici, alt sınıfların ebeveynlerinin gerektirdiği protokolü izlemelerini sağlar.
johnbakers

@johnbakers Oh evet, şimdi görüyorum. Açıklama için teşekkürler.
Binarian

Çok temiz uygulama ve herhangi parametrelerde geçen gereksiz acele önler object'sinit fonksiyonu
Sylvan D Ash

0

Bir sınıf nesnesinin bir dizisinin öğelerini kopyalamak istiyorsanız. Daha sonra NSCopying protokolünü kullanmadan aşağıdaki kodu takip edebilirsiniz, ancak nesneniz için gerekli olan tüm parametreleri alması gereken bir init yöntemine sahip olmanız gerekir. İşte oyun alanında test etmek için bir örnek için kod.

class ABC {
    
    var a = 0
    func myCopy() -> ABC {
        
        return ABC(value: self.a)
    }
    
    init(value: Int) {
        
        self.a = value
    }
}

var arrayA: [ABC] = [ABC(value: 1)]
var arrayB: [ABC] = arrayA.map { $0.myCopy() }

arrayB.first?.a = 2
print(arrayA.first?.a)//Prints 1
print(arrayB.first?.a)//Prints 2
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.