提问人:Martin Janiczek 提问时间:10/27/2009 更新时间:10/8/2021 访问量:7736
在 Mathematica 中显示重复项
Show duplicates in Mathematica
问:
在 Mathematica 中,我有一个列表:
x = {1,2,3,3,4,5,5,6}
我将如何列出重复项?喜欢:
{3,5}
我一直在将列表视为集合,如果列表有类似 Except[] 的东西,所以我可以做:
unique = Union[x]
duplicates = MyExcept[x,unique]
(当然,如果 x 有两个以上的重复项 - 例如,{1,2,2,2,3,4,4},则输出将为 {2,2,4},但额外的 Union[] 将解决这个问题。
但是没有这样的东西(如果我确实很好地理解了那里的所有功能)。
那么,如何做到这一点呢?
答:
有很多方法可以像这样进行列表提取;这是我想到的第一件事:
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
评论
Select[Tally[x], #[[2]]>1&][[All,1]]
%[[All,1]]
f@x
f[x]
给定一个列表 A,
获取 B 中的非重复值 B = DeleteDuplicates[A] 获取 C 中的重复值 C = Complement[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,所以这里的语法可能完美,也可能不完美。只需查看您链接到的页面上的文档即可。
评论
以下是在列表中单次完成此操作的方法:
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]
威尔·罗伯逊(Will Robertson)的解决方案可能更好,因为它更直接,但我认为如果你想提高速度,这应该会赢。但是,如果你关心这一点,你就不会用 Mathematica 编程了!:)
评论
i
i[n_]:=(i[n]=Unevaluated@Sequence[];n)
Tally
使用像 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 superior) 解决方案生成的输出并不完全匹配,因为元素将按照可以确定它们是重复项的顺序出现在返回的列表中。我不确定它是否真的可以在一次传递中完成,我能想到的所有方法实际上都涉及至少两次传递,尽管一次可能只在重复的元素上。
以下是 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
评论
["NonzeroPositions"]
这是 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# 类似于 MMA,而 C# 类似于 MMA。Where
Select
Select
Map
编辑:添加了可选的测试函数参数,默认为 .SameQ
编辑:这是一个版本,它解决了我在下面的评论,并报告了给定投影仪功能的组中的所有等效项,该投影仪功能产生一个值,如果该值相等,则列表的元素被视为等效的。这实质上是查找比给定大小更长的等价类:
reportDuplicateClusters[list_List, projector_: (# &),
minimumClusterSize_: 2] :=
GatherBy[list, projector] //
Select[#, Length@# >= minimumClusterSize &] &
下面是一个示例,用于检查整数对的第一个元素,如果它们的第一个元素相等,则认为两对整数相等
reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]
评论
这个线程看起来很旧,但我不得不自己解决这个问题。
这有点粗糙,但这能做到吗?
Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]
另一个短暂的可能性是
Last /@ Select[Gather[x], Length[#] > 1 &]
上一个:Linq 类型转换问题
下一个:如何查找列表中元素的长度?
评论
Union[Complement[x,Union[x]]
Complement[x,Union[x]]