13

在 Mathematica 我有一个列表:

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

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

{3,5}

我一直在将Lists 视为 Sets,如果列表中有诸如 except[] 之类的东西,那么我可以这样做:

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

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

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

那么,该怎么做呢?

4

8 回答 8

13

有很多方法可以像这样进行列表提取;这是我想到的第一件事:

部分[选择[Tally@x, 部分[#, 2] > 1 &], 全部, 1]

或者,更易于阅读:

理货@x
选择[%, 部分[#, 2] > 1 &]
部分[%, 全部, 1]

分别给出

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

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

顺便说一句,如果列表未排序,那么您需要Sort先对其运行,然后才能正常工作。

于 2009-10-27T14:39:36.580 回答
7

这是一种通过列表一次性完成的方法:

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 中编程了!:)

于 2009-10-27T17:17:26.853 回答
7

以下是 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相对于 pure 几乎没有开销Tally

于 2011-03-09T22:36:44.333 回答
4

使用像 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 高级)解决方案产生的输出不完全匹配,因为元素将按照可以确定它们是重复的顺序出现在返回的列表中。我不确定它是否真的可以一次完成,我能想到的所有方法实际上都涉及至少两次,尽管一次可能只在重复的元素上。

于 2009-10-27T20:01:46.570 回答
2

这是罗伯逊答案的一个版本,它使用 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]] &]
于 2011-12-29T18:04:25.767 回答
2

这个线程似乎很旧,但我必须自己解决这个问题。

这有点粗鲁,但是这样做吗?

Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]
于 2012-07-30T16:53:23.840 回答
1

给定一个列表 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,所以这里的语法可能完美也可能不完美。只需查看您链接到的页面上的文档即可。

于 2009-10-27T14:39:54.020 回答
1

另一个简短的可能性是

Last /@ Select[Gather[x], Length[#] > 1 &]
于 2021-10-07T18:41:16.163 回答