2011-03-09 45 views
9

我正在生成10^6至10^7实数的平面列表,其中一些正在重复。删除重复列表元素,保留外观顺序

我需要删除重复的实例,只保留第一次出现,而不修改列表顺序。

这里的关键是效率,因为我有很多要处理的列表。

实施例(假):

输入:

{.8, .3 , .8, .5, .3, .6} 

所需的输出

{.8, .3, .5, .6} 

除了注意

删除重复与联盟元件(不保留顺序)给出在我可怜的人的手中OP:

DiscretePlot[a = RandomReal[10, i]; [email protected]@[email protected], {i, 10^6 [email protected]}] 

enter image description here

回答

9

你想DeleteDuplicates,它保留列表顺序:

In[13]:= DeleteDuplicates[{.8, .3, .8, .5, .3, .6}] 

Out[13]= {0.8, 0.3, 0.5, 0.6} 

它在数学7.0加入。

+4

@Michael:我宁愿使用'DeleteDuplicates [...,Equal]',因为这些数字是真实的,默认比较是'SameQ'。慢得多,但更健壮。 – 2011-03-09 13:59:28

+0

确实,一个很好的建议! – 2011-03-09 14:01:08

+0

嗯,我总是忘记像'DeleteDuplicates'这样的内建插件。对于它的价值,作为一个内置的运行,在我的回答中,比'unsortedUnion'运行速度提高了3-6倍。 (请注意,这是使用'SameQ'而不是'Equal'。) – rcollyer 2011-03-09 15:06:24

5

对于7之前的Mathematica版本,为了大家的兴趣,下面介绍几种实现UnsortedUnion(即DeleteDuplicates)函数的方法。这些是从帮助文档和MathGroup收集的。他们已被调整为接受多个名单,然后加入,类似于联盟。

对于数学4或更早

UnsortedUnion = Module[{f}, f[y_] := (f[y] = Sequence[]; y); f /@ [email protected]##] & 

对于数学5

UnsortedUnion[x__List] := Reap[Sow[1, [email protected]], _, # &][[2]] 

对于数学6

UnsortedUnion[x__List] := Tally[[email protected]][[All, 1]] 

从列昂尼德·希夫林的数学3+

unsortedUnion[x_List] := Extract[x, Sort[Union[x] /. Dispatch[MapIndexed[Rule, x]]]] 
+1

@Mr。这里没有“考古学家徽章”! +1 – 2011-03-09 18:57:11

+0

@belisarius lol :-) – 2011-03-09 20:41:14

+0

尽管它可能无关紧要,但Ted Ersek指出,UnsortedUnion版本1将失败,并列出{3,1,1,f [3],3,2 ,f [3],1,1,8,2,6,8}。(他讨论了这个函数的起源,{原来是Carl Woll?} [这里](http://www.verbeia.com/mathematica/tips/Tricks.html),在'Clever Little Programs'的版本中:ClearAll DeleteRepititions [x _]:= Module [{t},t [n_]:=(t [n] = Sequence []; n); t/@ x]) – tomd 2011-03-10 13:54:27

9

不与其他竞争的答案,但我就是忍不住分享Compile(?) - 基础的解决方案。该解决方案基于构建二叉搜索树,然后检查列表中的每个数字,列表中的索引是否是构建B树时使用的索引。如果是,那么它是原始号码,如果不是 - 它是重复的。什么使得这个解决方案对我来说很有意思,就是它展示了一种模拟Compile“通过参考”的方法。关键在于,如果我们将编译函数内联到其他编译函数中(并且可以通过“InlineCompiledFunctions”选项实现),我们可以在内函数中引用外函数范围中定义的变量(因为内联函数的方式) 。这不是一个真正的通过引用,但它仍然允许从小块组合函数,而没有效率惩罚(这更符合宏观扩展的精神)。我不认为这是记录,并不知道这是否会留在未来的版本。不管怎么说,这里是代码:

(* A function to build a binary tree *) 
Block[{leftchildren , rightchildren}, 
makeBSearchTree = 
Compile[{{lst, _Real, 1}}, 
Module[{len = Length[lst], ctr = 1, currentRoot = 1}, 
leftchildren = rightchildren = Table[0, {Length[lst]}]; 
For[ctr = 1, ctr <= len, ctr++, 
    For[currentRoot = 1, lst[[ctr]] != lst[[currentRoot]],(* 
    nothing *), 
    If[lst[[ctr]] < lst[[currentRoot]], 
    If[leftchildren[[currentRoot]] == 0, 
    leftchildren[[currentRoot]] = ctr; 
    Break[], 
    (* else *) 
    currentRoot = leftchildren[[currentRoot]] ], 
    (* else *) 
    If[rightchildren[[currentRoot]] == 0, 
    rightchildren[[currentRoot]] = ctr; 
    Break[], 
    (* else *) 
    currentRoot = rightchildren[[currentRoot]]]]]]; 
], {{leftchildren, _Integer, 1}, {rightchildren, _Integer, 1}}, 
CompilationTarget -> "C", "RuntimeOptions" -> "Speed", 
CompilationOptions -> {"ExpressionOptimization" -> True}]]; 


(* A function to query the binary tree and check for a duplicate *) 
Block[{leftchildren , rightchildren, lst}, 
isDuplicate = 
Compile[{{index, _Integer}}, 
Module[{currentRoot = 1, result = True}, 
While[True, 
    Which[ 
    lst[[index]] == lst[[currentRoot]], 
    result = index != currentRoot; 
    Break[], 
    lst[[index]] < lst[[currentRoot]], 
    currentRoot = leftchildren[[currentRoot]], 
    True, 
    currentRoot = rightchildren[[currentRoot]] 
    ]]; 
result 
], 
{{leftchildren, _Integer, 1}, {rightchildren, _Integer, 
    1}, {lst, _Real, 1}}, 
CompilationTarget -> "C", "RuntimeOptions" -> "Speed", 
CompilationOptions -> {"ExpressionOptimization" -> True} 
]]; 


(* The main function *) 
Clear[deldup]; 
deldup = 
Compile[{{lst, _Real, 1}}, 
    Module[{len = Length[lst], leftchildren , rightchildren , 
    nodup = Table[0., {Length[lst]}], ndctr = 0, ctr = 1}, 
makeBSearchTree[lst]; 
For[ctr = 1, ctr <= len, ctr++, 
If[! isDuplicate [ctr], 
    ++ndctr; 
    nodup[[ndctr]] = lst[[ctr]] 
    ]]; 
Take[nodup, ndctr]], CompilationTarget -> "C", 
"RuntimeOptions" -> "Speed", 
CompilationOptions -> {"ExpressionOptimization" -> True, 
"InlineCompiledFunctions" -> True, 
"InlineExternalDefinitions" -> True}]; 

下面是一些测试:

In[61]:= intTst = [email protected][{0,500000},1000000]; 

In[62]:= (res1 = deldup[intTst ])//Short//Timing 
Out[62]= {1.141,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}} 

In[63]:= (res2 = Tally[intTst,Equal][[All,1]])//Short//Timing 
Out[63]= {0.64,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}} 

In[64]:= res1==res2 
Out[64]= True 

不为Tally版本,但也Equal快 - 基础的,正如我所说,我的观点是说明一个有趣的(IMO)技术。

+0

我不明白你写的内容的一半,所以我不得不相信你知道你在做什么,但它听起来很酷,所以+1。有一天,我将不得不学习更低级的语言,然后也许我会理解。 – 2011-03-09 20:31:38

+0

@Leonid +1感谢您分享这些想法。我相信我会学到很多东西 – 2011-03-10 00:03:41

+1

@Leonid这是一个有趣的技术,有点非常规的使用'编译'。如果您的编译代码受到编译代码回调到Mathematica的影响,性能会受到影响。你可以通过加载'Needs [“CompiledFunctionTools”](n.b .:使用反引号)和评估'CompilePrint [makeBSearchTree]'来看到它们。您会看到“MainEvaluate”的出现,意思是回拨给Mathematica。 – Sasha 2011-04-22 15:38:54

相关问题