根据Mathematica中的其他列表值拆分列表

Max*_*Max 3 wolfram-mathematica list

在Mathematica中,我有一个点坐标列表

size = 50;
points = Table[{RandomInteger[{0, size}], RandomInteger[{0, size}]}, {i, 1, n}];
Run Code Online (Sandbox Code Playgroud)

以及这些点所属的集群索引列表

clusterIndices = {1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1};
Run Code Online (Sandbox Code Playgroud)

根据clusterIndices值将点分成两个单独的列表的最简单方法是什么?

编辑:我提出的解决方案:

pointIndices =
  Map[#[[2]] &,
    GatherBy[MapIndexed[{#1, #2[[1]]} &, clusterIndices], First],
    {2}];
pointsByCluster = Map[Part[points, #] &, pointIndices];
Run Code Online (Sandbox Code Playgroud)

有更好的方法吗?

rco*_*yer 5

正如@High Performance Mark和@Nicholas Wilson所说,我首先将两个列表组合在一起Transpose或通过Thread.在这种情况下,

In[1]:= Transpose[{clusterIndices, points}]==Thread[{clusterIndices, points}]
Out[1]:= True
Run Code Online (Sandbox Code Playgroud)

有一次,我看着哪个更快,我认为Thread速度稍快.但是,只有在使用很长的列表时才真正重要.

@High Performance Mark在建议方面提出了一个很好的观点Select.但是,它只允许您一次拉出一个群集.选择集群1的代码如下:

Select[Transpose[{clusterIndices, points}], #[[1]]==1& ][[All, All, 2]]
Run Code Online (Sandbox Code Playgroud)

由于您似乎想要生成所有集群,我建议您执行以下操作:

GatherBy[Transpose[{clusterIndices, points}], #[[1]]& ][[All, All, 2]]
Run Code Online (Sandbox Code Playgroud)

这是一个单线程的优点,唯一棘手的部分是选择正确Part的结果列表.确定需要多少All条款的诀窍就是要注意这一点

Transpose[{clusterIndices, points}][[All,2]]
Run Code Online (Sandbox Code Playgroud)

需要从转置列表中取回积分.但是,"聚集"列表有一个额外的级别,因此第二个级别All.

应该注意的是,第二个参数GatherBy是一个接受一个参数的函数,它可以与你想要使用的任何函数互换.因此,它非常有用.但是,如果您想将数据转换为收集数据,我会看看Reap并且Sow.

编辑: Reap并且Sow有些使用不足,相当强大.它们使用起来有些混乱,但我怀疑它GatherBy是在内部使用它们实现的.例如,

Reap[ Sow[#[[2]], #[[1]] ]& /@ Transpose[{clusterIndices, points}], _, #2& ]
Run Code Online (Sandbox Code Playgroud)

与我以前的代码做同样的事情,没有从点上剥离指数的麻烦.基本上,Sow标记每个点的索引,然后Reap收集所有标记(_对于第二个参数)并仅输出点.就个人而言,我使用它而不是GatherBy,我已将其编码为我加载的函数,如下所示:

SelectEquivalents[x_List,f_:Identity, g_:Identity, h_:(#2&)]:=
   Reap[Sow[g[#],{f[#]}]&/@x, _, h][[2]];
Run Code Online (Sandbox Code Playgroud)

注意:此代码是5.x中帮助文件中的修改形式.但是,6.0和7.0帮助文件删除了许多有用的示例,这就是其中之一.


Mic*_*lat 5

这是一个简洁的方法,使用SplitBy7.0版中的新功能,应该非常快:

SplitBy[Transpose[{points, clusterIndices}], Last][[All, All, 1]]
Run Code Online (Sandbox Code Playgroud)

如果您不使用7.0,则可以将其实现为:

Split[Transpose[{points, clusterIndices}], Last[#]==Last[#2]& ][[All, All, 1]]
Run Code Online (Sandbox Code Playgroud)

更新

对不起,我没有看到你只想要两个组,我认为它们是聚类,而不是分裂.这是一些代码:

FindClusters[Thread[Rule[clusterIndices, points]]]
Run Code Online (Sandbox Code Playgroud)