Ubah objek yang namanya berdasarkan isi array

Saya memiliki vektor dua elemen yang elemennya hanya boleh 0 atau 1. Untuk contoh ini, misalkan x = [0, 1]. Misalkan juga ada empat objek y00, y01, y10, y11. Tujuan saya adalah memperbarui y yang sesuai (y01 dalam contoh ini) sesuai dengan nilai x saat ini.

Saya sadar saya dapat melakukan ini menggunakan serangkaian pernyataan if:

if x == [0, 0]
    y00 += 1
elseif x == [0, 1]
    y01 += 1
elseif x == [1, 0]
    y10 += 1
elseif x == [1, 1]
    y11 += 1
end

Namun, saya memahami hal ini dapat dilakukan dengan lebih ringkas menggunakan metaprogramming Julia, meskipun Saya tidak terbiasa dengan penggunaannya dan tidak tahu caranya. Saya ingin dapat mengungkapkan sesuatu seperti y{x[1]}{x[2]} += 1 (yang jelas-jelas salah); pada dasarnya, dapat merujuk dan memodifikasi y yang benar sesuai dengan nilai x saat ini. Sejauh ini, saya sudah bisa memanggil nilai sebenarnya dari y yang benar (tapi saya tidak bisa memanggil objek y itu sendiri) dengan sesuatu seperti

eval(Symbol(string("y", x[1], x[2])))

Saya minta maaf jika saya tidak menggunakan istilah yang tepat, tapi saya harap saya sudah menjelaskannya dengan jelas.


person han-tyumi    schedule 04.01.2020    source sumber
comment
Karena Anda mengetahui indeks Anda adalah vektor dua elemen, Anda pasti akan lebih baik (dari segi kinerja) menggunakan tupel (i,j) daripada vektor [i,j]   -  person François Févotte    schedule 05.01.2020


Jawaban (3)


Ada cara yang jauh lebih elegan menggunakan StaticArrays. Anda dapat menentukan tipe umum untuk nilai y Anda, yang akan berperilaku seperti matriks (yang menurut saya diwakili oleh ys?), dan mendefinisikan banyak hal untuk Anda:

julia> mutable struct Thing2 <: FieldMatrix{2, 2, Float64}
           y00::Float64
           y01::Float64
           y10::Float64
           y11::Float64
       end

julia> M = rand(Thing2)
2×2 Thing2 with indices SOneTo(2)×SOneTo(2):
 0.695919  0.624941 
 0.404213  0.0317816

julia> M.y00 += 1
1.6959194941562996

julia> M[1, 2] += 1
1.6249412302897646

julia> M * [2, 3]
2-element SArray{Tuple{2},Float64,1,2} with indices SOneTo(2):
 10.266662679181893 
  0.9037708026795666

(Catatan tambahan: Indeks Julia dimulai dari 1, jadi mungkin lebih idiomatis jika menggunakan indeks berbasis satu untuk y juga. Alternatifnya, dapat membuat tipe array dengan pengindeksan khusus, tapi itu lebih merepotkan lagi.)

person phipsgabler    schedule 04.01.2020
comment
Mungkin lebih tepat untuk pertanyaan spesifik ini: x=(0,1); M[CartesianIndex(x.+1)] += 1 - person François Févotte; 05.01.2020

Bagaimana kalau menggunakan x sebagai indeks linier ke dalam array Y?

x = reshape(1:4, 2, 2)
Y = zeros(4);
Y[ x[1,2] ] += 1
person Tasos Papastylianou    schedule 04.01.2020
comment
Ini tidak benar-benar menjawab pertanyaan tersebut - dan memerlukan restrukturisasi atas arti x tanpa benar-benar menjelaskannya secara memadai IMO. - person mbauman; 06.01.2020
comment
@MattB. Saya tidak mengerti alasannya. OP sendiri yang mengatakan bahwa 0 vs 1 hanyalah saran. Julia berbasis 1, bukan 0, jadi 1 vs 2 lebih masuk akal. Dan secara umum, memberi nama variabel sebagai y00, y01 daripada menggunakan array tidak disarankan dalam bahasa apa pun. - person Tasos Papastylianou; 06.01.2020
comment
Saya hanya mengatakan Saya pada awalnya tidak mengerti bagaimana Anda menyusun ulang contoh tersebut. Saya hanya berpikir Anda memerlukan lebih banyak penjelasan tentang bagaimana Anda mengubah prompt dan bagaimana pembingkaian ulang tersebut memecahkan keinginan mendasar dalam pertanyaan tersebut. Mungkin suara negatifnya terlalu keras, tapi itulah mengapa saya pikir ada baiknya menambahkan jawaban saya sendiri. - person mbauman; 06.01.2020
comment
@MattB. Ya, cukup adil, saya melihat jawaban Anda (+1) tepat setelah komentar ini dan mungkin itulah yang Anda maksud di sini. :) Ach, saya tidak setuju... hanya saja berkali-kali di sini saya menemukan (yang membuat saya terkejut dan kecewa) kebanyakan orang yang menanyakan pertanyaan seperti ini tidak peduli (atau membaca) penjelasan yang rumit , dan lebih memilih cuplikan singkat yang menyelesaikan masalahnya. Jadi saat ini saya menjaga semuanya sesingkat mungkin, dan setidaknya mencoba untuk memiliki kode yang tidak dikaburkan, dengan harapan bahwa bermain dengan kode yang disediakan akan memberikan wawasan yang diperlukan dalam potongan yang lebih kecil yang dapat dicerna. - person Tasos Papastylianou; 07.01.2020
comment
@MattB. yang lebih menyedihkan lagi, pengalaman saya di situs ini menunjukkan bahwa kode yang sama persis yang diringkas menjadi lebih sedikit baris memiliki peluang lebih besar untuk dibaca daripada kode dengan spasi yang tepat, meskipun versi yang diringkas jauh lebih jelek. Frustrasi, tapi, apa yang bisa Anda lakukan. - person Tasos Papastylianou; 07.01.2020

Setiap kali Anda menamai variabel dengan nomor urut, itu adalah BENDERA MERAH BESAR sehingga Anda sebaiknya menggunakan array saja. Tidak perlu membuatnya terlalu rumit dengan array statis khusus atau pengindeksan linier — Anda cukup membuat y array 2x2 biasa saja. Transformasi langsungnya adalah:

y = zeros(2,2)
if x == [0, 0]
    y[1,1] += 1
elseif x == [0, 1]
    y[1,2] += 1
elseif x == [1, 0]
    y[2,1] += 1
elseif x == [1, 1]
    y[2,2] += 1
end

Sekarang Anda dapat mulai melihat polanya di sini dan menyederhanakannya dengan menggunakan x sebagai indeks langsung ke y:

y[(x .+ 1)...] += 1

Saya melakukan dua hal di sana: Saya menambahkan satu ke semua elemen x dan kemudian saya menciptakan elemen tersebut ke dalam ekspresi pengindeksan sehingga dianggap sebagai pencarian dua dimensi. Dari sini, Anda dapat menjadikannya lebih Julian dengan hanya menggunakan indeks berbasis satu sejak awal dan berpotensi menjadikan x menjadi Tuple atau CartesianIndex untuk meningkatkan kinerja.

person mbauman    schedule 06.01.2020