在mathematica中使用map / select查找列表中的子列表

时间:2011-06-01 13:33:02

标签: list wolfram-mathematica

我在Wolfram Mathematica 8.0中有一个像

这样的嵌套列表

nList = {{a,b},{f,g},{n,o}}

之类的普通列表

lList = {a,b,c,k,m,n,o,z}

我想检查nList中的所有子列表是否都在lList中(在示例中a,b和n,o是否存在但不是f,g)

我使用For[,,,]并使用索引来完成它...有人可以启发我使用Map / Thread / Select等函数来一次性完成。

修改:如果nList包含a,blList必须包含a,b而不是a,c,bb,ab,c,a < / p>

2 个答案:

答案 0 :(得分:9)

假设您不关心元素排序,这里有一种方法:

In[20]:= Complement[Flatten[nList],lList] ==={}

Out[20]= False

修改

如果订单很重要,那么这是一种方式:

In[29]:= And@@(MatchQ[lList,{___,PatternSequence[##],___}]&@@@nList)

Out[29]= False

对于大量子列表,这可能会更快:

In[34]:= 
Union[ReplaceList[lList,
       {___,x:Alternatives@@(PatternSequence@@@nList),___}:>{x}]]===Union[nList]

Out[34]= False

这的工作原理如下:ReplaceList是一个非常好但经常被忽略的命令,它返回一个所有可能表达式的列表,这些表达式可以通过模式匹配器尝试以一切可能的方式将规则应用于表达式来获得。这与模式匹配器通常的工作方式形成对比,它在第一次成功匹配时停止。 PatternSequence是Mathematica模式语言的一个相对较新的补充,它允许我们为给定的表达序列赋予身份,将其视为模式。这允许我们构造替代模式,因此得到的模式是:主要列表中任何位置的任何子列表的序列被收集并放回到列表括号中,形成子列表。我们得到尽可能多的新形成的子列表,因为在较大的列表中存在原始子列表的序列。如果所有子列表都存在,则结果列表中的Union应与原始子列表列表的Union相同。

以下是基准测试(我列出了整数列表,以及由Partition生成的重叠子列表):

In[39]:= tst = Range[1000];

In[41]:= sub = Partition[tst, 2, 1];

In[43]:= 
And @@ (MatchQ[tst, {___, PatternSequence[##], ___}] & @@@ sub) // Timing

Out[43]= {3.094, True}

In[45]:= 
Union[ReplaceList[tst, {___,x : Alternatives @@ (PatternSequence @@@ sub), ___} 
     :> {x}]] ===  Union[sub] // Timing

Out[45]= {0.11, True}

从概念上讲,第二种方法更快的原因是它在列表的单次运行中执行其工作(由ReplaceList内部执行),而第一种解决方案显式遍历每个子列表的大列表-list。

编辑2 - 效果

如果性能确实是个问题,那么以下代码的速度要快得多:

And @@ (With[{part = Partition[lList, Length[#[[1]]], 1]},
 Complement[#, part] === {}] & /@SplitBy[SortBy[nList, Length], Length])

例如,在我们的基准测试中:

In[54]:= And@@(With[{part = Partition[tst,Length[#[[1]]],1]},
       Complement[#,part]==={}]&/@SplitBy[SortBy[sub,Length],Length])//Timing

Out[54]= {0.,True}

编辑3

根据@ Mr.Wizard的建议,可以进行以下性能改进:

Scan[
 If[With[{part = Partition[lList, Length[#[[1]]], 1]},
   Complement[#, part] =!= {}], Return[False]] &,
 SplitBy[SortBy[nList, Length], Length]
] === Null

在这里,只要我们从给定长度的子列表中得到否定答案,就不会检查其他长度的子列表,因为我们已经知道答案是否定的(False)。如果Scan在没有Return的情况下完成,则会返回Null,这意味着lList包含nList中的所有子列表。

答案 1 :(得分:5)

您可以使用模式匹配来完成这项工作:

In[69]:= nList = {{a, b}, {f, g}, {n, o}};
lList = {a, b, c, k, m, n, o, z};

@@@Apply{1}的别名。 nList的第1级包含您的对,并且应用使用List右侧的函数替换其中的头部@@@

In[71]:= MatchQ[lList, {___, ##, ___}] & @@@ nList

Out[71]= {True, False, True}