我想将 METAPOST 数组的所有值设置到一行中,就像在其他编程语言中编写的那样。
在我能找到的所有示例或手册示例中,人们都单独定义数组元素,如果数组很长,我会觉得非常繁琐:
pair B[];
B1 :=(5,60);
B2 := ...
etc...
除其他外,我尝试了以下方法,但都产生错误:
B[] := ((5,60),(5,-115),(10,180));
B := (5,60),(5,-115),(10,180);
B := [(5,60),(5,-115),(10,180)];
....
有没有综合方法来设置大数组的值?我找不到任何参考资料,在 metapost 中甚至可能都不可能?
答案1
类似数组的命名约定是 MetaPost 的构造B[1]
,E[3]
具有所谓的下标(在我们的例子中是1
和3
),而不是真正的数组,MetaPost 无法处理。但是,作为宏语言,您可以定义自己的宏来自动创建对(如果我使用了错误的术语,请纠正我):
vardef ListofPairs(suffix $)(text Pairs) =
save i_; i_ := 0; %save makes i_ local
pair $[]; %define a pair with the variable name $
%Typical loop over passed elements
for i = Pairs: $[i_] := i; i_ := i_ + 1; endfor;
enddef;
ListofPairs(B)((5,60),(5,-115),(10,180));
drawdot B[0] withpen pensquare scaled 12 withcolor red;
drawdot B[1] withpen pencircle scaled 10 withcolor green;
drawdot B[2] withpen pencircle scaled 8 withcolor blue;
友情建议,不要指望 MetaPost 像“普通”编程语言。相反,MetaPost 手册是一个很好的起点(texdoc metapost
如果您安装了完整的发行版)。METAFONTBook也推荐,但说实话我还没读过。
答案2
这个答案实际上只不过是对另一个答案的评论,但评论框太小了。Metapost 中有几个有用的内置功能和宏可以plain.mp
帮助完成此类任务。
考虑下面的小程序:
vardef makePairs@#(text arguments) =
save i; numeric i; i = -1;
pair @#[];
for t = arguments:
@#[incr i] = t;
endfor;
enddef;
makePairs B ((0,1), (1, 2), (2, 3));
for i=0 upto 9:
if known B[i]: show i; show B[i]; fi
endfor
end
如果你运行它,mpost
你应该得到以下输出
>> 0
>> (0,1)
>> 1
>> (1,2)
>> 2
>> (2,3)
笔记
_
我避免在变量名中使用尾随,以避免在 中覆盖某些内容的可能性plain.mp
,其中_
在内部变量的名称中使用我使用了特殊的后缀参数符号
@#
来代替分隔suffix
参数。这允许使用稍微更“自然”的语法;用户可以这样写makePairs B ((0,1),....)
而不是makePairs(B)((0,1),...)
。之后
save i
,我将其重新声明i
为数字,这样任何先前的值都会被删除。这只是一个好习惯。我使用宏
incr
来plain.mp
增加索引,而不是使用笨重的i := i + 1
语法。最后,我使用 来
known
检查我的“数组”中是否定义了特定的后缀。在 Metapost 中,带有数字后缀的变量与其他语言中的数组完全不同,尽管外观如此。因此,可以定义B[0]
和B[2]
,而无需定义B[1]
,并且无法检查后缀变量的“长度”。
进一步简化
如果您喜欢上述内容,请注意您可以从最后一个参数中省略括号,这样我们可以让语法对用户来说更加简单,如下所示:
vardef declarePairs@# text arguments =
save i; numeric i; i = -1;
pair @#[];
for t = arguments:
@#[incr i] = t;
endfor;
enddef;
declarePairs B (0,1), (1, 2), (2, 3);
for i=0 upto 9:
if known B[i]: show i; show B[i]; fi
endfor
end
还有另一个想法
根据您想要对“数组”中的所有对执行的操作,另一种可能性是将它们全部创建为一个path
:
path p;
p = (0,1) .. (1,2) .. (2,3);
然后你可以得到每一对point 0 of p
,point 1 of p
您实际上不必绘制路径,您可以将其用作某种列表结构。在本例中,MP做提供一个length
命令,然后您可以将其反转reversed
或对整个过程进行某些简单的算术运算。例如,p := p shifted up
将ypart
路径中每个点的加 1。