如何在Mathematica中删除表格中的空符号?

12

我需要在Table循环中使用If语句,例如Table[If[i< 3, i], {i, 5}]将返回{1, 2, Null, Null, Null}

但我希望结果是{1,2}

有什么解决方法吗?

编辑:
如果我们考虑Table[If[i< 3, f[i]], {i, 5}],它将返回{f[1], f[2], Null, Null, Null}


有点相关的问题:https://dev59.com/uljUa4cB1Zd3GeqPOSL7 - Mr.Wizard
相关问题:http://mathematica.stackexchange.com/questions/3700/how-to-avoid-returning-a-null-if-there-is-no-else-condition-in-an-if-contruct - anderstood
5个回答

33

简洁地说:

Table[If[i < 3, i, ## &[]], {i, 5}]

这个方法有效是因为函数 ## & 不会立即执行。

## & 是一种“消失”的函数。

{1, 2, ## &[], 3, 4}
----> {1, 2, 3, 4}
请参阅SlotSequence,以了解更多信息。

1
@Leonid 感谢您几个月前向我展示或提醒我的事情。 - Mr.Wizard
3
我想这是你的发明。我通常使用Sequence@@{},它不太优雅(也许稍微慢一点)。 - Leonid Shifrin
@Leonid; 我相信那是正确的,不过在那之前我一直在If内部使用 Unevaluated @ Sequence []。 (顺便问一句,你知道除了谷歌以外如何搜索评论吗?我想找到那个交流。) - Mr.Wizard

15

如果你需要从现有列表中删除它,可以使用

DeleteCases[list, Null]
或者
list /. Null -> Sequence[]

(稍微高级一些)。


关于你上面的Table示例,首先请注意,If中的第二个逗号是不必要的(甚至会被标为粉色):

list = Table[If[i < 3, i], {i, 5}]

要根据条件筛选表格元素,您可能需要使用类似于以下内容的东西

list = Select[Table[i, {i, 5}], # < 3 &]

最后,如果你需要生成一个列表但不想将被拒绝的元素添加到其中(以节省内存),我建议使用ReapSow

Reap@Do[If[i < 3, Sow[i]], {i, 5}]
list = %[[2, 1]]

我并没有实际验证过这种方法与普通的Table相比所使用的内存量,但是需要注意的是,如果你只生成可以存储在打包数组中的数字,那么Table结构可能更加内存高效。另一方面,如果你生成了大量的通用表达式,其中大多数将被If拒绝,那么Sow/Reap可能更好。


+1. 我实际上在我链接的答案中完全使用了您最后一个建议的 Reap-Sow,在我的答案中(只是条件语法可能更友好)。 - Leonid Shifrin

6

作为替代方案,您可以使用此答案中的Table变体,该变体专门设计用于条件表格构建。下面是它的外观:

In[12]:= tableGenAltMD[i,{i,5},#<3&]
Out[12]= {1,2}

最后一个参数是表示条件的函数。实际上,如果能够直接使用i(和/或其他迭代器变量)也很好,这样的语法可能不难添加。

请考虑阐述为什么这可能比我下面给出的简单答案更可取。 - Mr.Wizard
1
@Mr. Wizard,原因很简单:这是一个通用函数(我的版本)。它还可以处理多维情况,并具有统一的语法。它仍然更易于阅读,当我添加用表达式替换条件函数的语法时,它将变得更加容易。如果它是内置函数或只是WRI批准的函数,那么就不会有使用其他任何东西的问题了。想象一下,如果您没有Cases,而有人给您提供了一个(在顶层实现),您不会使用它吗(如果实现正确)?很多时候这只是习惯、约定等问题。 - Leonid Shifrin
也许你应该在你的回答中包含那个?;-) - Mr.Wizard
@Mr.Wizard 不这么认为 :). 里面有足够的信息,需要的人会找到它。 - Leonid Shifrin
除非你执意要删除先前的评论,否则至少它现在已经在这个页面上了。+1 - Mr.Wizard
@Mr.Wizard 我会保留这个评论的 :). 感谢您的点赞。 - Leonid Shifrin

4
在之前的回答中,部分 ## &[] 可以替换为内置符号 Nothing
Table[If[i < 3, i, Nothing], {i, 5}]

提供

{1, 2}

3
如果您使用Sequence[]而不是Null,那么可以执行以下操作:
Table[If[i < 3, i, Hold[Sequence[]]] // ReleaseHold, {i, 5}]

我很长一段时间都希望 If 有一个属性 SequenceHold。我想我曾经向WRI建议过这个想法,但是可能有(好?)理由使得If没有这个属性。 如果敢于更改内置符号(应该不应该这样做),可以尝试:

Unprotect[If];
SetAttributes[If, SequenceHold];

那么在If语句中,Sequence[]只会起作用:

Table[If[i < 3, i, Sequence[]], {i, 5}]

Rolf,请查看我刚刚添加的答案。我差点编辑了你的问题而不是发布它,但我意识到这样做实际上会用我的答案替换你的答案,所以我没有这样做。 - Mr.Wizard
Mr. Wizard:非常好!我不知道##&@[]是Sequence[]的等效物。 - Rolf Mertig

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