Показать дубликаты в 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}, но дополнительное объединение[] решит это.)
но там не было что-нибудь в этом роде (если бы я хорошо понимал все функции).
Итак, как это сделать?
7 ответов
много способов сделать извлечение списка, как это; вот первое, что пришло мне на ум:
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
на нем сначала перед этим будет работать.
вот способ сделать это в один проход по списку:
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! :)
вот несколько более быстрых вариантов метода подсчета.
f4
использует "трюки", данные Карлом Воллом и Оливером Рубенкоенигом в 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
!
использование решения, такого как dreeves, но только возврат одного экземпляра каждого дублированного элемента, немного сложнее. Один из способов сделать это заключается в следующем:
collectDups1[l_] :=
Module[{i, j},
i[n_] := (i[n] := j[n]; Unevaluated@Sequence[]);
j[n_] := (j[n] = Unevaluated@Sequence[]; n);
i /@ l];
Это не точно соответствует выходу, полученному решением Уилла Робертсона (IMO superior), потому что элементы будут отображаться в возвращаемом списке в том порядке, в котором можно определить, что они дублируются. Я не уверен, что это действительно можно сделать за один проход, все способы, которые я могу придумать, включают, фактически, по крайней мере два прохода, хотя один может быть только над дублированными элементами.
вот версия ответа Робертсона, которая использует 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# ' S Where
это как у ММА Select
и C#'ы Select
это как у ММА Map
.
EDIT: добавлен необязательный аргумент тестовой функции, по умолчанию SameQ
.
EDIT: вот версия, которая обращается к моему комментарию ниже и сообщает обо всех эквивалентах в группе, заданной функцией проектора, которая создает значение, такое, что элементы списка считаются эквивалентными, если значение равно. Это по существу находит классы эквивалентности длиннее заданного размера:
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]]
учитывая список A,
вам не повторяющиеся значения в B
B = DeleteDuplicates[A]
получить повторяющиеся значения в C
C = Дополнение[A, B]
получите не повторяющиеся значения из списка дубликатов в D
D = DeleteDuplicates[C]
вот пример:
А = 1, 2, 2, 2, 3, 4, 4
B = 1, 2, 3, 4
C = 2, 2, 4
D = 2, 4
таким образом, ваш ответ будет DeleteDuplicates[дополнение[x, DeleteDuplicates[x]]] где x это твой список. Я не знаю mathematica, поэтому синтаксис может быть или не быть идеальным здесь. Просто врачи на странице вы связаны.