Изменить объект, имя которого основано на содержимом массива

У меня есть двухэлементный вектор, элементы которого могут быть только 0 или 1. Ради этого примера предположим, что x = [0, 1]. Предположим также, что есть четыре объекта y00, y01, y10, y11. Моя цель — обновить соответствующий y (в данном примере y01) в соответствии с текущим значением x.

Я знаю, что могу сделать это, используя серию операторов 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

Однако я понимаю, что это можно сделать более кратко, используя метапрограммирование Джулии, хотя Я не знаком с его использованием и не могу понять, как это сделать. Я хочу иметь возможность выразить что-то вроде y{x[1]}{x[2]} += 1 (что явно неправильно); в основном, иметь возможность ссылаться и изменять правильный y в соответствии с текущим значением x. До сих пор мне удавалось вызвать фактическое значение правильного y (но я не могу вызвать сам объект y) с помощью чего-то вроде

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

Извините, если я использовал неподходящий жаргон, но, надеюсь, я ясно выразился.


person han-tyumi    schedule 04.01.2020    source источник
comment
Поскольку вы знаете, что ваши индексы являются двухэлементными векторами, вам определенно будет лучше (с точки зрения производительности) использовать кортежи (i,j) вместо векторов [i,j]   -  person François Févotte    schedule 05.01.2020


Ответы (3)


Есть гораздо более элегантный способ использования StaticArrays. Вы можете определить общий тип для ваших значений y, который будет вести себя как матрица (которую, как я предполагаю, представляют ys?), и определяет для вас множество вещей:

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

(Примечание: индексы Джулии начинаются с 1, поэтому было бы более идиоматично использовать индексы, основанные на единице, и для y. Альтернативно, может создавать типы массивов с настраиваемой индексацией, но это опять же больше работы.)

person phipsgabler    schedule 04.01.2020
comment
Возможно, больше подходит для этого конкретного вопроса: x=(0,1); M[CartesianIndex(x.+1)] += 1 - person François Févotte; 05.01.2020

Как насчет использования x в качестве линейных индексов в массиве Y?

x = reshape(1:4, 2, 2)
Y = zeros(4);
Y[ x[1,2] ] += 1
person Tasos Papastylianou    schedule 04.01.2020
comment
На самом деле это не отвечает на подсказку и требует реструктуризации того, что означает x, без адекватного описания IMO. - person mbauman; 06.01.2020
comment
@МэттБ. Я не понимаю, почему. ОП сами сказали, что 0 против 1 было просто предложением. Джулия отсчитывается от 1, а не от 0, поэтому 1 против 2 имеет больше смысла. И вообще, имена переменных как y00, y01 вместо использования массива не рекомендуются ни для одного языка. - person Tasos Papastylianou; 06.01.2020
comment
Я просто говорю, что я сначала не понял, как вы переформулировали пример. Я просто думаю, что вам нужно немного больше объяснений о том, как вы меняете подсказку и как это переосмысление решает скрытое желание в вопросе. Возможно, голосование было слишком резким, но именно поэтому я подумал, что стоит добавить свой собственный ответ. - person mbauman; 06.01.2020
comment
@МэттБ. Да, честно говоря, я увидел ваш ответ (+1) сразу после этого комментария и понял, что, вероятно, вы имели в виду именно это. :) Ах, я не согласен ... просто снова и снова я обнаруживал (к моему удивлению и разочарованию), что большинство людей, которые задают такого рода вопросы, не заботятся (или не читают) подробные объяснения , и предпочитают короткие фрагменты, которые решают их проблему. Так что в эти дни я делаю вещи как можно более краткими и, по крайней мере, стараюсь иметь незапутанный код в надежде, что игра с предоставленным кодом даст необходимые идеи в меньшем удобоваримом фрагменте. - person Tasos Papastylianou; 07.01.2020
comment
@МэттБ. что еще более удручающе, мой опыт на сайте показал мне, что точно такой же код, сжатый до меньшего количества строк, имеет больше шансов быть прочитанным, чем код с правильными интервалами, даже если сжатая версия намного уродливее. Обидно, но что поделаешь. - person Tasos Papastylianou; 07.01.2020

Каждый раз, когда вы обнаружите, что называете переменные последовательными номерами, это ОГРОМНЫЙ КРАСНЫЙ ФЛАГ, что вместо этого вы должны просто использовать массив. Нет необходимости усложнять это с помощью пользовательского статического массива или линейной индексации — вы можете просто сделать y обычным массивом 2x2. Прямое преобразование:

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

Теперь вы можете увидеть здесь шаблон и упростить его, используя x в качестве индекса непосредственно в y:

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

Здесь я делаю две вещи: добавляю единицу ко всем элементам x, а затем включаю эти элементы в выражение индексации, чтобы они обрабатывались как двумерный поиск. Отсюда вы можете сделать это более юлианским, просто используя индексы на основе единицы с самого начала и потенциально превращая x в Tuple или CartesianIndex для повышения производительности.

person mbauman    schedule 06.01.2020