Показать дубликаты в Mathematica
-
06-07-2019 - |
Вопрос
В Mathematica у меня есть список:
x = {1,2,3,3,4,5,5,6}
Как мне составить список с дубликатами? Как:
{3,5}
Я просматривал списки как наборы , если есть что-то вроде За исключением [] для списков, так что я мог бы сделать:
unique = Union[x]
duplicates = MyExcept[x,unique]
(Конечно, если x будет иметь более двух дубликатов - скажем, {1, 2,2,2 , 3,4,4}, то результат будет {2, 2,4}, но дополнительный Союз [] решит это.)
Но ничего подобного не было (если я хорошо понял все функции).
Итак, как это сделать?
Решение
Множество способов для извлечения списка, подобного этому; вот первое, что пришло мне в голову:
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! :) Р>
Вот несколько быстрых вариантов метода Tally.
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), потому что элементы будут отображаться в возвращаемом списке в том порядке, в котором можно определить, что они являются дубликатами. Я не уверен, что это действительно можно сделать за один проход, все способы, которые я могу придумать, включают, по крайней мере, два прохода, хотя один может быть только над дублированными элементами. Р>
Вот вариант ответа Робертсона, который использует 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 # похож на Select
в MMA, а Select
в C # похож на карту
MMA.
РЕДАКТИРОВАТЬ: добавлен необязательный аргумент тестовой функции, по умолчанию SameQ
.
РЕДАКТИРОВАТЬ: вот версия, в которой указан мой комментарий ниже & amp; сообщает обо всех эквивалентах в группе с заданной функцией проектора, которая выдает значение, так что элементы списка считаются эквивалентными, если значение равно. По сути, это находит классы эквивалентности длиннее заданного размера:
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]]
Учитывая список А,
получить неповторяющиеся значения в 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, поэтому синтаксис может быть или не быть идеальным здесь. Просто перейдите к документам на странице, на которую вы ссылаетесь.