Untuk memastikan nilai Swift sintetik kekal unik tanpa mengubah tertib sisipannya, imbas tatasusunan input sekali, jejak kunci yang diterima dalam set, dan tambahkan hanya kemunculan pertama pada tatasusunan output. Panduan ini membina pengiraan setempat ringkas yang boleh anda jalankan pada Mac.

Tugasnya ialah memproses senarai tersusun nilai bentuk sintetik, membuang nilai berulang, dan mengira jumlah daripada entri yang dikekalkan. Semuanya berlaku dalam memori; contoh ini tidak membaca input luaran dan tidak menyimpan hasil pengiraan.

Tentukan maksud “unik” sebelum memilih koleksi

Tatasusunan Swift mengekalkan tertib dan membenarkan pendua. Set mengandungi nilai unik tetapi tidak mempunyai tertib yang ditetapkan. Oleh itu, menukar tatasusunan kepada set kemudian kembali kepada tatasusunan tidak mengekalkan tertib kemunculan pertama. Pengisihan selepas itu menetapkan tertib pengisihan, yang mungkin berbeza daripada tertib sisipan. Tingkah laku koleksi ini didokumenkan dalam Jenis Koleksi Swift.

Dalam contoh ini, setiap nilai sintetik mempunyai nama bentuk dan saiz. Kontrak lalai menganggap dua entri sebagai pendua hanya apabila kedua-dua sifatnya sepadan. Oleh itu, bulatan bersaiz 12 dan bulatan bersaiz 20 kekal sebagai nilai berasingan.

Soalan tentang kontrak Peraturan untuk pengiraan ini
Apakah yang menentukan tertib input? Kedudukan dalam tatasusunan yang diberikan
Apakah yang menjadikan dua nilai pendua? Bentuk dan saiz yang sama
Kemunculan yang manakah dikekalkan? Kemunculan pertama
Adakah pendua yang muncul kemudian mengalihkan nilai yang dikekalkan? Tidak
Apakah yang berlaku jika input kosong? Pulangkan tatasusunan kosong dan jumlah sifar
Nilai yang manakah menyumbang kepada jumlah? Hanya nilai yang dikekalkan

Kontrak ini mengelakkan kesilapan mudah: membuang entri berdasarkan nama bentuk apabila pengiraan memerlukan gabungan bentuk dan saiz yang berbeza. Contoh lengkap ini juga mengira hasil berdasarkan bentuk sahaja supaya anda dapat melihat kesan perubahan peraturan itu.

Bina contoh Swift setempat yang lengkap pada Mac anda

Anda memerlukan toolchain Swift yang telah dipasang. Dalam Terminal, jalankan swift --version untuk mengesahkan bahawa arahan itu tersedia. Tutorial rasmi Swift, Bina Alat Baris Perintah, mendokumenkan semakan itu, penciptaan pakej boleh laku dan cara menjalankan pakej.

Cipta direktori baharu untuk contoh ini dan mulakan pakej boleh laku:

mkdir OrderDemo
cd OrderDemo
swift package init --name OrderDemo --type executable

Gantikan fail sumber boleh laku yang dijana di bawah Sources dengan program lengkap di bawah. Nama fail dan susun atur direktori yang dijana mungkin berbeza mengikut toolchain; gantikan titik masuk sedia ada dan bukannya menambah titik masuk kedua. Program ini menggunakan titik masuk @main, jadi letakkannya dalam fail bernama OrderDemo.swift, dengan menamakan semula main.swift yang dijana jika perlu. Tutorial baris perintah Swift menerangkan pilihan antara fail main.swift dengan titik masuk @main.

Tiada import atau kebergantungan pakej diperlukan. Program ini menggunakan jenis dan fungsi pustaka standard.

struct Tile: Hashable {
    let shape: String
    let size: Int
}

func uniqueFirst<Value, Key: Hashable>(
    _ values: [Value],
    by key: (Value) -> Key
) -> [Value] {
    var seen: Set<Key> = []
    var result: [Value] = []

    for value in values {
        if seen.insert(key(value)).inserted {
            result.append(value)
        }
    }

    return result
}

@main
struct OrderDemo {
    static func main() {
        let input = [
            Tile(shape: "circle", size: 12),
            Tile(shape: "square", size: 8),
            Tile(shape: "circle", size: 12),
            Tile(shape: "circle", size: 20),
            Tile(shape: "square", size: 8)
        ]

        let retained = uniqueFirst(input, by: { $0 })
        let total = retained.reduce(0) { $0 + $1.size }
        let skipped = input.count - retained.count

        let expected = [
            Tile(shape: "circle", size: 12),
            Tile(shape: "square", size: 8),
            Tile(shape: "circle", size: 20)
        ]
        precondition(retained == expected)
        precondition(total == 40)
        precondition(skipped == 2)

        let empty: [Tile] = []
        precondition(uniqueFirst(empty, by: { $0 }).isEmpty)
        precondition(
            uniqueFirst([input[0], input[0]], by: { $0 })
                == [input[0]]
        )

        let byShape = uniqueFirst(input, by: { $0.shape })
        precondition(byShape == [input[0], input[1]])
        let shapeTotal = byShape.reduce(0) { $0 + $1.size }
        precondition(shapeTotal == 20)

        for tile in retained {
            print("\(tile.shape): \(tile.size)")
        }
        print("Total: \(total)")
        print("Skipped duplicates: \(skipped)")
        print("Shape-only total: \(shapeTotal)")
    }
}

Dari direktori pakej, jalankan:

swift run OrderDemo

Output program yang dijangka, selepas sebarang mesej binaan, ditunjukkan di bawah. Program ini disemak berdasarkan dokumentasi API yang diperoleh tetapi tidak dijalankan di sini kerana persekitaran penyelidikan ini tiada boleh laku Swift.

circle: 12
square: 8
circle: 20
Total: 40
Skipped duplicates: 2
Shape-only total: 20

Mengapakah pendekatan tatasusunan dan set mengekalkan tertib?

Tatasusunan ialah satu-satunya sumber tertib output. Gelung melawati setiap kedudukan input mengikut turutan, dan append(_:) meletakkan nilai yang diterima di hujung hasil. Set hanya menentukan sama ada kunci yang dipilih pernah muncul; program ini tidak mengulanginya.

Ungkapan penting ialah seen.insert(key(value)).inserted. Swift mendokumenkan bahawa insert(_:) memulangkan inserted sebagai true untuk ahli baharu dan false apabila ahli yang sama sudah wujud. Ahli sedia ada kekal tidak berubah. Nilai pulangan itu membolehkan satu operasi menentukan sama ada nilai asal perlu ditambahkan. Lihat dokumentasi sisipan Set Apple.

Bagi input yang diberikan, bulatan dan segi empat sama yang pertama diterima. Bulatan kedua yang serupa dilangkau. Bulatan yang lebih besar diterima kerana nilai penuhnya berbeza, manakala segi empat sama yang berulang dilangkau. Oleh itu, saiz yang dikekalkan ialah 12 + 8 + 20 = 40.

Pelaksanaan ini mengekalkan invarian yang berguna: selepas setiap lelaran, hasil mengandungi tepat nilai terawal yang ditemui bagi setiap kunci dalam seen, mengikut tertib kemunculannya. Kunci baharu memanjangkan kedua-dua koleksi; kunci berulang tidak mengubah mana-mana koleksi. Penaakulan ini menerangkan jaminan tertib tanpa bergantung pada cara set menyimpan ahlinya.

Bagaimanakah nilai Swift tersuai patut menyatakan kesamaan?

Pengisytiharan struct Tile: Hashable meminta pematuhan yang disintesis. Kedua-dua sifat tersimpan, String dan Int, boleh dicincang, jadi Swift boleh mensintesis tingkah laku yang diperlukan. Apple mendokumenkan syarat pensintesisan ini dalam Hashable.

Menggunakan { $0 } sebagai kunci menjadikan keseluruhan nilai Tile penentu keunikan. Menggunakan { $0.shape } mengubah kontrak kepada satu entri yang dikekalkan bagi setiap bentuk. Dalam contoh ini, hal itu membuang bulatan bersaiz 20 yang muncul kemudian, lalu mengurangkan jumlah kepada 20. Ini ialah perbandingan sengaja antara dua peraturan, bukannya pelaksanaan kedua bagi peraturan yang sama.

Pastikan pemilihan kunci ditentukan secara konsisten sepanjang pengiraan. Terbitkannya daripada nilai yang sedang diproses, bukannya daripada pembilang atau pemboleh ubah luaran yang berubah. Jika tidak, input yang sama boleh menerima kunci yang berbeza lalu kekal sebagai entri berasingan.

Jika anda melaksanakan kesamaan dan pencincangan secara manual, gunakan sifat penting yang sama bagi kedua-duanya. Apple mensyaratkan supaya tika yang sama memasukkan nilai yang sama ke dalam pencincang mengikut urutan yang sama. Elakkan menggunakan hashValue itu sendiri sebagai kunci keunikan: cincangan bukan pengganti kontrak kesamaan nilai. Dengan mengekalkan kunci sebenar yang boleh dicincang, set boleh menerapkan kontrak itu. Lihat syarat pematuhan Hashable.

Bilakah anda patut menggunakan koleksi tertib sebaliknya?

Untuk pengiraan tunggal ini, tatasusunan bersama set setempat menjadikan tingkah lakunya jelas. Jika aplikasi kerap menambah, membuang, menyusun semula dan mencari ahli unik, koleksi tertib khusus boleh memudahkan penyelenggaraan operasi tersebut.

Pilihan Keadaan yang sesuai Batasan berkaitan
Tatasusunan bersama set Satu laluan melalui nilai Swift sintetik, mungkin menggunakan kunci pilihan Fungsi anda menentukan tingkah laku kemunculan pertama
Swift Collections OrderedSet Penggunaan berterusan koleksi tertib yang mengandungi nilai boleh dicincang yang unik Memerlukan pakej Swift Collections yang berasingan
Foundation NSOrderedSet API sedia ada menggunakan koleksi objek tertib Foundation Kelas yang mewakili koleksi tertib statik; operasi boleh ubah menggunakan NSMutableOrderedSet

Dokumentasi rasmi Swift Collections menerangkan OrderedSet sebagai koleksi unsur unik yang tersusun, diimport melalui OrderedCollections. Ia menyediakan operasi yang mengambil kira kedudukan seperti append(_:) dan insert(_:at:). Itu ialah API pakej, jadi menambah import OrderedCollections sahaja tidak mengkonfigurasi projek yang selainnya tidak mempunyai kebergantungan. Lihat OrderedSet.

Dokumentasi Foundation Apple menerangkan NSOrderedSet sebagai koleksi statik objek berbeza yang tersusun dan mengenal pasti NSMutableOrderedSet sebagai padanan boleh ubahnya. Untuk pengiraan nilai Swift natif di atas, fungsi generik menyatakan kunci kesamaan yang dipilih secara langsung tanpa memperkenalkan koleksi objek itu. Lihat NSOrderedSet.

Apakah perubahan apabila pengiraan digunakan oleh antara muka desktop?

Contoh lengkap ini adalah segerak dan memiliki koleksi sementaranya di dalam fungsi. Untuk senarai sintetik yang kecil, ini memberikan satu tertib pemprosesan yang jelas tanpa memperkenalkan tugasan.

Dalam antara muka macOS, asingkan keadaan dan kemas kini yang berkaitan dengan UI dengan sewajarnya. Apple mendokumenkan MainActor sebagai aktor global yang pelaksananya setara dengan baris gilir penghantaran utama; panduan keserentakan Swift menerangkan penggunaan @MainActor pada fungsi dan jenis yang mengakses keadaan antara muka. Lihat MainActor dan Keserentakan.

Keserentakan juga memerlukan takrif tertib yang jelas. Swift tidak menjamin tertib penyelesaian tugasan anak dalam kumpulan tugasan. Oleh itu, menambahkan hasil apabila tugasan selesai mengekalkan tertib penyelesaian, yang mungkin berbeza daripada tertib input asal. Panduan keserentakan rasmi mendokumenkan batasan ini.

Jika versi akan datang menjalankan pengiraan sintetik bebas secara serentak, sertakan kedudukan setiap input bersama hasilnya, pulihkan tertib berdasarkan kedudukan input selepas pengumpulan, kemudian lakukan laluan keunikan. Reka bentuk ini diterbitkan daripada batasan tertib penyelesaian yang didokumenkan itu. Kekalkan contoh kecil semasa dalam keadaan segerak melainkan kerja tambahan memerlukan penyelarasan tambahan.

Semak kontrak sebelum menggunakan semula fungsi

Program ini merangkumi semakan untuk tertib kekal yang tepat, input kosong, nilai serupa yang berulang dan peraturan alternatif berdasarkan bentuk sahaja. Semakan ini menyasarkan keputusan yang paling berkemungkinan mengubah makna pengiraan.

Apabila menyesuaikannya, semak tiga syarat: input mesti sudah mempunyai tertib yang bermakna, kunci mesti menyatakan peraturan kesamaan yang anda inginkan, dan pengekalan kemunculan pertama mestilah sesuai. Fungsi ini sengaja melangkau entri sepadan yang muncul kemudian; ia tidak menggabungkan saiznya atau menggantikan nilai yang dikekalkan. Bilangan yang dilangkau menjadikan kesan itu jelas.

Bagi senarai bentuk sintetik yang diberikan, hasil akhirnya ialah tiga nilai mengikut tertib kemunculan pertama dan jumlah 40. Biarkan tatasusunan mengawal tertib, set mengawal keahlian, dan kunci yang dipilih menentukan maksud “unik”.

Sumber