在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 []会解决这个问题。)
但是没有那样的东西(如果我确实理解了那里的所有功能)。
那么,该怎么做?
答案 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,所以这里的语法可能也可能不完美。只需访问您链接到的页面上的文档。