我尝试使用功能方式解决这个问题,但我没有取得多大成功。
假设有一个列表列表,并且只需要选择其中具有特定位置唯一条目的列表。
例如,假设有一个矩阵,我们只想选择第一列中具有唯一元素的行。
以下是一个例子:
INPUT:
list= {{ 1,2}, {1,3},{4,5}}
我希望输出为
list={{1,2},{4,5}}
删除哪个“行”并不重要,第一个是好的,但任何一个都没问题。
我尝试过Select,DeleteCases,DeleteDuplicates,Union等等,但是无法让它工作。我不知道如何告诉Mathematica只寻找'独特'元素。联盟接近但它完整列表。即我不知道为标准写什么,如
DeleteDuplicates[list, <now what?> ]
作为参考,这就是我在Matlab中执行上述操作的方法:
EDU>> A=[1 2;1 3;4 5]
A =
1 2
1 3
4 5
EDU>> [B,I,J]=unique(A(:,1));
EDU>> A(I,:)
ans =
1 3
4 5
感谢
答案 0 :(得分:8)
这是一种方式:
DeleteDuplicates[list, First@#1 === First@#2 &]
编辑
请注意,下面的时间安排和讨论基于M7
经过反思,我找到了一个解决方案,对于大型列表来说(至少)数量级会快一些,对于这种特殊情况,有时会快两个数量级(可能,更好的方法就是下面的解决方案将具有不同的计算复杂度):
Clear[delDupBy];
delDupBy[nested_List, n_Integer] :=
Module[{parts = nested[[All, n]], ord, unpos},
ord = Ordering[parts];
unpos = Most@Accumulate@Prepend[Map[Length, Split@parts[[ord]]], 1];
nested[[Sort@ord[[unpos]]]]];
基准:
In[406]:=
largeList = RandomInteger[{1,15},{50000,2}];
In[407]:= delDupBy[largeList,1]//Timing
Out[407]= {0.016,{{13,4},{12,1},{1,6},{6,13},{10,12},{7,15},{8,14},
{14,4},{4,1},{11,9},{5,11},{15,4},{2,7},{3,2},{9,12}}}
In[408]:= DeleteDuplicates[largeList,First@#1===First@#2&]//Timing
Out[408]= {1.265,{{13,4},{12,1},{1,6},{6,13},{10,12},{7,15},{8,14},{14,4},
{4,1},{11,9},{5,11},{15,4},{2,7},{3,2},{9,12}}}
这一点尤为引人注目,因为DeleteDuplicates
是一个内置函数。我可以盲目猜测,DeleteDuplicates
用户定义的测试使用二次时成对比较算法,而delDupBy
是n*log n
列表的大小。
我认为这是一个重要的教训:在使用自定义测试时,应该注意内置函数,例如Union
,Sort
,DeleteDuplicates
等。我在this Mathgroup主题中更广泛地讨论了它,其中还有其他有见地的回复。
最后,让我提一下,在here之前,已经提出了这个问题(强调效率)。我将在这里重现一个解决方案,当第一个(或通常是n
- th)元素是正整数时,我给出了一个解决方案(推广到任意整数很简单)。:
Clear[sparseArrayElements];
sparseArrayElements[HoldPattern[SparseArray[u___]]] := {u}[[4, 3]]
Clear[deleteDuplicatesBy];
Options[deleteDuplicatesBy] = {Ordered -> True, Threshold -> 1000000};
deleteDuplicatesBy[data_List, n_Integer, opts___?OptionQ] :=
Module[{fdata = data[[All, n]], parr,
rlen = Range[Length[data], 1, -1],
preserveOrder = Ordered /. Flatten[{opts}] /. Options[deleteDuplicatesBy],
threshold = Threshold /. Flatten[{opts}] /. Options[deleteDuplicatesBy], dim},
dim = Max[fdata];
parr = If[dim < threshold, Table[0, {dim}], SparseArray[{}, dim, 0]];
parr[[fdata[[rlen]]]] = rlen;
parr = sparseArrayElements@If[dim < threshold, SparseArray@parr, parr];
data[[If[preserveOrder, Sort@parr, parr]]]
];
这种方法的工作方式是使用第一个(或通常是n
- 个)元素作为某些位置
我们预先分配的巨大表,利用它们是正整数)。在某些情况下,这个可以给我们疯狂的表现。观察:
In[423]:= hugeList = RandomInteger[{1,1000},{500000,2}];
In[424]:= delDupBy[hugeList,1]//Short//Timing
Out[424]= {0.219,{{153,549},{887,328},{731,825},<<994>>,{986,150},{92,581},{988,147}}}
In[430]:= deleteDuplicatesBy[hugeList,1]//Short//Timing
Out[430]= {0.032,{{153,549},{887,328},{731,825},<<994>>,{986,150},{92,581},{988,147}}}
答案 1 :(得分:0)
列昂尼德提供了一个长期而彻底的答案,就像他经常做的那样。但是,我认为值得指出的是,可以采用以下方式提供一种有效而简洁的解决方案:
First /@ GatherBy[hugeList, #[[1]] &]
其中1
是要比较的列索引。
在我的系统上,这比delDupBy
快,但不如deleteDuplicatesBy
快。