用列表创建变量字符串

5
我想知道是否可以使用变量列表中的内容创建一个新变量。
例如:
str={"cow","monkey"}

这些字符串是从文件中提取的。现在我想把这些字符串当作变量来引用。因此,变量"cow"可以设置为{4,2,3}或任何其他值。任何如str[[1]]的引用都会返回字符串"cow"。
有什么提示吗?还是说这个想法本身就不好?
当然,我可以在已有的列表中添加信息,例如:
str={{"cow",{4,2,3}},{"monkey",{}}

但是即使这样,我仍然不能直接将cow作为一个变量来使用。


欢迎来到stackoverflow Lou!别忘了为你喜欢的答案投票,如果其中一个回答满足了你的问题,请使用答案旁边的勾选标记接受它。你可以随时更改你的选择。 - Sjoerd C. de Vries
3个回答

4
最简单的方法是手动使用符号cowmonkey,而不是字符串:
In[309]:= 
cow = 1;
monkey = 2;  
{cow, monkey}

Out[311]= {1, 2}

但这可能不是你所问的。如果你想自动将字符串转换为变量,那么你要做的(如果我正确理解了问题)是首先将字符串转换为符号,因为符号可以赋值并用作变量:

Remove[cow,monkey];
str = {"cow", "monkey"};
str1 = ToExpression /@ str

{cow, monkey}

我假设符号cowmonkey未被使用/定义。之后,您可以使用this问题的答案根据它们在str1中的位置分配变量。然而,这种方法的实用性也值得怀疑。

我认为最有意义的是创建所谓的索引变量,例如

myIndexedVar["cow"] = 1;
myIndexedVar["monkey"] = 2;

其中myIndexedVar本质上是一个键值对的哈希表,其中键是您的字符串,值是您想要分配给它们的任何内容。如果需要,可以自动化该过程。

编辑

为了说明对这些变量的分配,这里有一个自动化该过程的函数:

assignVariables[varNames_List, values_List, hashName_Symbol ] /; 
  Length[varNames] == Length[values] :=
    MapThread[(hashName[#1] = #2) &, {varNames, values}];

这是如何使用它的:

In[316]:= assignVariables[str,{{4,2,3},{}},myIndexedVar]

Out[316]= {{4,2,3},{}}

In[317]:= myIndexedVar["cow"]

Out[317]= {4,2,3}

In[318]:= myIndexedVar["monkey"]

Out[318]= {}

但是,这实际上是一个哈希表,所以当你重述问题为:“我想要创建一个带有字符串键的哈希表。在Mathematica中,最简单的方法是什么,如何添加键值对并访问它们?”时,你的问题就更有意义了。答案似乎是 - 索引变量,就像上面所示的那样。您可能还会发现阅读DownValues很有用,因为它们为索引变量提供了机制。


3
你也可以使用 Symbol[],例如 Symbol /@ {"cow", "monkey"}。我建议使用索引变量。或者可以使用替换列表或分派表:values = Dispatch[{"cow" -> {4,2,3},"monkey" -> {}}]"cow" /. values。这可以确保不会意外地与已存在的符号发生冲突。 - Szabolcs
@Szabolcs,Dispatch 的一个问题是,一旦形成了 Dispatch 规则,就不能轻松地添加新的键值对,而不会造成与此相关的性能损失(别误会 - 我非常喜欢 Dispatch :))。此外,我认为索引变量对于来自其他语言的用户更直观,他们可能理解哈希表,但以前没有看到过替换规则。 - Leonid Shifrin
这也在我的回答中:你使用 myIndexedVar["cow"] 暗示了你知道 "cow" 在列表中。如果你知道这一点,为什么不直接使用 符号 cow 呢?如果你不知道它在列表中,你也不能将字符串 "cow" 用作引用。 - Sjoerd C. de Vries
1
@Sjoerd 我认为在这种情况下使用符号非常脆弱,并且仅提到它们是为了给出完整的图片(实际上我链接到了其他SO问题,你的答案被接受了)- 人们仍然可以使用str1中符号的位置。至于如何使用字符串-请参见我的编辑-在那里我使用了str而不知道字符串“变量”的名称,只知道它们的编号。我并不是说这很明智,但至少这可能有些意义-如果想以某种自动方式向哈希添加键值对。此外,在发布我的回答时,我看不到你的回答 :) - Leonid Shifrin
@Sjoerd,这很不幸是真的,而且相当令人烦恼,但没有技术上的理由让它变成那样。我希望有一个函数可以将新值插入到调度表中。您是否了解调度和“函数定义”(即f["a"] = 2)在替换规则排序方面的任何差异? - Szabolcs
@Szabolcs 我理解你对 Dispatch 的痛苦。关于规则排序,据我所知,Dispatch 不会重新排序规则。DownValues 会重新排序,但是您可以向其传递 Sort->False 选项以查看原始规则排序。此外,在出现重复的规则左侧时,Dispatch 似乎会保留两个规则(尽管只使用第一个规则),而在 DownValues 中,仅存储具有相同左侧的最后输入规则。当然,这只告诉您可以从中提取什么 - 对于非模式,规则的使用方式基于两种情况下的内部哈希表。 - Leonid Shifrin

3
ToExpression函数可以将字符串转换为表达式。而Symbol["x"]则像其名称所示,创建了一个名为x的符号。
然而,我想知道您打算如何使用它们。如果您不知道文件中有哪些名称,那么您该如何使用它们呢?例如,如果str={"cow","monkey"},我使用strSym=ToExpression/@str创建了一个符号列表,则我只能通过索引这个第二个数组来继续我的代码。我不能简单地在我的代码中写cow=5,因为我不知道在编写代码时是否会有一个名为cow的变量。
In[1]:= str = {"cow", "monkey"};
strSym = ToExpression /@ str

Out[2]= {cow, monkey}

In[3]:= strSym[[1]] // Evaluate = 5

Out[3]= 5

In[4]:= ?cow

Global`cow

cow=5

正如您所看到的,索引也需要额外的Evaluate,因为Set(=)具有HoldFirst属性。因此,除非我评估了索引,否则我无法通过索引设置cow,否则会覆盖strSym [[1]]的定义。


@所有人,谢谢大家的快速回复。这回答了我的问题并引发了一些新的问题 :). 我觉得索引变量将是最好的选择。我理解Sjoerd关于使用先验未知变量的问题。我考虑使用这个模型来使代码更易读,它不应该是一个固定的独立程序,而是一个交互式的研究笔记本。 - Lou

3

Leonid的方法可能是最好的,但我喜欢使用替换规则,因此我提供以下方法:

str={"cow","monkey"};

rules = {"cow" -> {4,2,3}, "monkey" -> {}};

str[[1]] /. rules
输出结果为 {4, 2, 3}

请参考 RuleReplaceAll 获取更多信息。


2
这种方法的优点是最为干净 - 它不会引入副作用,完全是声明式的。缺点是对于初学者来说,它会产生更多的问题(例如:什么是替换规则,如何修改它们的右手边,效率如何,规则排序如何等)。我建议的方法也基于(全局)替换规则,并且(我认为)是避免可变代码和保持简单性之间的一个很好的折衷(特别是对于来自其他语言的用户)。 - Leonid Shifrin
这条评论完全不是对你的帖子的批评(我已经点赞了),只是一条补充信息 :) - Leonid Shifrin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接