Как установить значения для символов - PullRequest
5 голосов
/ 18 апреля 2011

Я хотел бы установить значения в списке переменных, например:

list[[1]] = 2

и если list[[1]] равно a, то a теперь будет равно двум. Как мне этого добиться?

Ответы [ 4 ]

9 голосов
/ 19 апреля 2011

Ну, давайте попробуем наивно:

Составить список:

In[1]:= ClearAll[list, a, b, c]; 
list = {a, b, c}; 

Это так, как мы ожидаем:

In[3]:= list
Out[3]= {a, b, c}

Установить для первого элемента значение 2:

In[4]:= list[[1]] = 2
Out[4]= 2

In[5]:= list
Out[5]= {2, b, c}

Это не влияет на:

In[6]:= a 
Out[6]= a

Начать снова:

In[7]:= ClearAll[list, a, b, c]; 
list = {a, b, c}; 

In[9]:= list
Out[9]= {a, b, c}

Проблема в том, что Set (=) имеет HoldFirstкак один из его атрибутов, т. е. он не оценивает свой первый аргумент, который является левой стороной, и назначение относится к списку, а не к переменной, которая находится в этом месте.Но вы можете форсировать оценку, используя Evaluate:

In[10]:= Evaluate[list[[1]]] = 2
Out[10]= 2

Теперь список выглядит так же, как и раньше:

In[11]:= list
Out[11]= {2, b, c}

, но это только потому, что a все еще там и получилзначение 2 (в предыдущей версии a было заменено на 2):

In[12]:= a
Out[12]= 2

Если вы теперь установите значение 3, вы увидите, что этот список изменений тоже:

In[13]:= a = 3
Out[13]= 3

In[14]:= list
Out[14]= {3, b, c}

РЕДАКТИРОВАТЬ

Возможно, более близко к формулировке вашего вопроса, вы можете Map Set по списку:

In[16]:= ClearAll[list, a, b, c]; 
list = {a, b, c}; 

In[18]:= Set[#, RandomInteger[10]] & /@ list
Out[18]= {4, 8, 1}

In[19]:= list    
Out[19]= {4, 8, 1}

In[21]:= {a, b, c}    
Out[21]= {4, 8, 1}
9 голосов
/ 19 апреля 2011

То, что вы запрашиваете, обычно сложно в Mathematica, так как трудно имитировать семантику указателя.Следующий код будет делать именно то, что вы просили, но ограничен только символами в качестве элементов списка:

ClearAll[setPart];
SetAttributes[setPart, HoldFirst];
setPart[lst_Symbol, i_, value_] :=
  With[{heldPart =  First@Extract[Hold[lst] /. OwnValues[lst], {{1, i}}, Hold]},
    If[MatchQ[heldPart, Hold[_Symbol]],
      Set @@ Append[heldPart, value],
      lst[[i]] = value]];

Примеры:

In[117]:= Clear[list, a, b]
list = {a, b, c, 4, 5};
a = 1;
b = 3;
list

Out[121]= {1, 3, c, 4, 5}

In[122]:= setPart[list, 1, 10];
{a, list}

Out[123]= {10, {10, 3, c, 4, 5}}

In[124]:= setPart[list, 5, 10];
list

Out[125]= {10, 3, c, 4, 10}
2 голосов
/ 07 декабря 2014

У меня просто была похожая проблема с определением значения символов, когда вы впервые не знаете, какой символ вы хотите переопределить. Ваши ответы помогли мне найти правильный способ сделать это:

HoldPattern работал очень хорошо для меня здесь, даже если значения уже были установлены для переменных.

In[253]:= Clear[a,b,c,d,list]
list = HoldPattern/@{a,b,c,d};
a=2;
Evaluate[list[[1]]]=1;
list//ReleaseHold
a

Out[257]= {1,b,c,d}
Out[258]= 1

Таким образом, мое решение во многом похоже на первое решение Сьорда К. де Фриза, но оно защищает символы от оценки внутри списка HoldPattern.

Обратите внимание, что нужно использовать ReleaseHold , чтобы использовать список для дальнейших вычислений. На переменные (a, b, c, d) эта конструкция не влияет.

Это был мой первый пост здесь, надеюсь, вам понравится; -)

2 голосов
/ 19 апреля 2011

Возможно, вы могли бы сделать:

setSymbol[symbol_, value_] := Module[{},
    ToExpression[
        SymbolName[symbol] <> "=" <> ToString[value,TotalWidth->Infinity]
    ]
]
setSymbol[list[[1]], 2]

Хотя это может быть немного хакерским. Правильный путь - играть с тем, как значения удерживаются от оценки, но я не могу вспомнить, как; см. другие ответы.

...