在Mathematica中显示重复项

时间:2009-10-27 14:11:11

标签: list duplicates wolfram-mathematica

在Mathematica中我有一个列表:

x = {1,2,3,3,4,5,5,6}

如何制作包含重复项的列表?像:

{3,5}

我一直在查看Lists as Sets,如果列表中有[Except []之类的内容,那么我可以这样做:

unique = Union[x]
duplicates = MyExcept[x,unique]

(当然,如果x有两个以上的重复 - 比如,{1, 2,2,2 ,3,4,4},那么输出将为{2, 2,4},但是额外的Union []会解决这个问题。)

但是没有那样的东西(如果我确实理解了那里的所有功能)。

那么,该怎么做?

7 个答案:

答案 0 :(得分:11)

像这样做列表提取的方法很多;这是我想到的第一件事:

Part[Select[Tally@x, Part[#, 2] > 1 &], All, 1]

或者,更可读的是:

Tally@x
Select[%, Part[#, 2] > 1 &]
Part[%, All, 1]

分别给出

{{1, 1}, {2, 1}, {3, 2}, {4, 1}, {5, 2}, {6, 1}}
{{3, 2}, {5, 2}}
{3, 5}

也许你可以想到一种更有效(在时间或代码空间中)的方式:)

顺便说一句,如果列表未排序,那么您需要首先运行Sort才能生效。

答案 1 :(得分:6)

这是一种通过列表单次传递的方法:

collectDups[l_] := Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]

例如:

collectDups[{1, 1, 6, 1, 3, 4, 4, 5, 4, 4, 2, 2}] --> {1, 1, 4, 4, 4, 2}

如果你想要唯一重复的列表 - {1, 4, 2} - 那么将上面的内容包装在DeleteDuplicates中,这是另一个单一的遍历列表(Union效率较低,因为它也对结果进行排序。)

collectDups[l_] := 
  DeleteDuplicates@Block[{i}, i[n_]:= (i[n] = n; Unevaluated@Sequence[]); i /@ l]

罗伯逊的解决方案可能会更好,因为它更直接,但我认为如果你想要更快的速度,这应该会赢。但如果你关心这一点,你就不会在Mathematica中编程! :)

答案 2 :(得分:5)

以下是Tally方法的几种更快的变体。

f4使用Carl Woll和Oliver Ruebenkoenig在MathGroup上给出的“技巧”。

f2 = Tally@# /. {{_, 1} :> Sequence[], {a_, _} :> a} &;

f3 = Pick[#, Unitize[#2 - 1], 1] & @@ Transpose@Tally@# &;

f4 = # ~Extract~ SparseArray[Unitize[#2 - 1]]["NonzeroPositions"] & @@ Transpose@Tally@# &;

速度比较(包括f1以供参考)

a = RandomInteger[100000, 25000];

f1 = Part[Select[Tally@#, Part[#, 2] > 1 &], All, 1] &;

First@Timing@Do[#@a, {50}] & /@ {f1, f2, f3, f4, Tally}

SameQ @@ (#@a &) /@ {f1, f2, f3, f4}

Out[]= {3.188, 1.296, 0.719, 0.375, 0.36}

Out[]= True

令我惊讶的是f4相对于纯Tally几乎没有开销!

答案 3 :(得分:3)

使用类似dreeves的解决方案,但只返回每个重复元素的单个实例,有点棘手。一种方法如下:

collectDups1[l_] :=
  Module[{i, j},
    i[n_] := (i[n] := j[n]; Unevaluated@Sequence[]);
    j[n_] := (j[n] = Unevaluated@Sequence[]; n);
    i /@ l];

这与Will Robertson(IMO高级)解决方案产生的输出不完全匹配,因为元素将按照可以确定它们是重复的顺序出现在返回的列表中。我不确定它是否真的可以在一次通过中完成,我能想到的所有方式实际上至少涉及两次通过,尽管可能只有重复的元素。

答案 4 :(得分:1)

这是Robertson的答案版本,它使用100%“后缀表示法”进行函数调用。

identifyDuplicates[list_List, test_:SameQ] :=
 list //
    Tally[#, test] & //
   Select[#, #[[2]] > 1 &] & //
  Map[#[[1]] &, #] &

Mathematica的//类似于其他语言中方法调用的点。例如,如果它是用C#/ LINQ样式编写的,它就像

list.Tally(test).Where(x => x[2] > 1).Select(x => x[1])

请注意,C#的Where与MMA的Select类似,而C#的Select就像MMA的Map

编辑:添加了可选的测试函数参数,默认为SameQ

编辑:这是一个版本,可以在下面发表我的评论&报告给定投影仪函数的组中的所有等价物,其产生值,使得如果值相等则列表的元素被认为是等效的。这基本上可以找到等于给定大小的等价类:

reportDuplicateClusters[list_List, projector_: (# &), 
  minimumClusterSize_: 2] :=
 GatherBy[list, projector] //
  Select[#, Length@# >= minimumClusterSize &] &

这是一个检查第一个元素上的整数对的示例,如果它们的第一个元素相等,则考虑两个等价对

reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]

答案 5 :(得分:1)

这个帖子看起来很旧,但我必须自己解决这个问题。

这有点粗糙,但这样做了吗?

Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]

答案 6 :(得分:0)

给出一个清单A,
获得B中的非重复值 B = DeleteDuplicates [A]
在C中获取重复值 C =补充[A,B]
从D中的重复列表中获取非重复值 D = DeleteDuplicates [C]

所以你的例子:
A = 1,2,2,2,3,4,4 B = 1,2,3,4 C = 2,2,4 D = 2,4

所以你的答案是DeleteDuplicates [Complement [x,DeleteDuplicates [x]]],其中x是你的列表。我不知道mathematica,所以这里的语法可能也可能不完美。只需访问您链接到的页面上的文档。