Показать дубликаты в Mathematica
В Mathematica у меня есть список:
x = {1,2,3,3,4,5,5,6}
Как создать список с дубликатами? Как:
{3,5}
Я смотрел Lists as Sets, если для списков есть что-то вроде Except [], поэтому я мог бы сделать:
unique = Union[x]
duplicates = MyExcept[x,unique]
(Конечно, если x будет иметь более двух дубликатов - например, {1, 2,2,2, 3,4,4}, то выход будет {2, 2,4}, но дополнительный Союз [] решил бы это.)
Но не было ничего подобного (если бы я хорошо понимал все функции).
Итак, как это сделать?
Ответы
Ответ 1
Множество способов сделать извлечения списка таким образом; вот первое, что пришло мне в голову:
Part[Select[[email protected], Part[#, 2] > 1 &], All, 1]
Или, более читаемо в кусках:
[email protected]
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
, прежде чем это сработает.
Ответ 2
Здесь можно сделать это за один проход через список:
collectDups[l_] := Block[{i}, i[n_]:= (i[n] = n; [email protected][]); 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_] :=
[email protected][{i}, i[n_]:= (i[n] = n; [email protected][]); i /@ l]
Решение Robertson, вероятно, будет лучше, потому что оно более прямолинейно, но я думаю, что если вы хотите увеличить скорость, это должно победить. Но если бы вы позаботились об этом, вы бы не программировали в Mathematica!:)
Ответ 3
Вот несколько более быстрых вариаций метода Талли.
f4
использует "трюки", данные Карлом Воллем и Оливером Рюбенененигом в MathGroup.
f2 = [email protected]# /. {{_, 1} :> Sequence[], {a_, _} :> a} &;
f3 = Pick[#, Unitize[#2 - 1], 1] & @@ [email protected]@# &;
f4 = # ~Extract~ SparseArray[Unitize[#2 - 1]]["NonzeroPositions"] & @@ [email protected]@# &;
Сравнение скорости (f1
включено для справки)
a = RandomInteger[100000, 25000];
f1 = Part[Select[[email protected]#, Part[#, 2] > 1 &], All, 1] &;
[email protected]@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
!
Ответ 4
Использование решения, такого как трижды, но возвращающее только один экземпляр каждого дублированного элемента, немного зависит от сложной стороны. Один из способов сделать это:
collectDups1[l_] :=
Module[{i, j},
i[n_] := (i[n] := j[n]; [email protected][]);
j[n_] := (j[n] = [email protected][]; n);
i /@ l];
Это не точно соответствует результату, полученному решением Will Robertson (IMO superior), поскольку элементы появятся в возвращенном списке в том порядке, в котором можно определить, что они дубликаты. Я не уверен, действительно ли это может быть сделано за один проход, все способы, по которым я могу думать, включать, по сути, как минимум два прохода, хотя можно было бы только пережить дублированные элементы.
Ответ 5
Вот вариант ответа Робертсона, который использует 100% -ную "постфиксную нотацию" для вызовов функций.
identifyDuplicates[list_List, test_:SameQ] :=
list //
Tally[#, test] & //
Select[#, #[[2]] > 1 &] & //
Map[#[[1]] &, #] &
Mathematica //
похожа на точку вызова метода на других языках. Например, если это было написано в стиле С#/LINQ, оно будет напоминать
list.Tally(test).Where(x => x[2] > 1).Select(x => x[1])
Обратите внимание, что С# Where
похож на MMA Select
, а С# Select
похож на MMA Map
.
EDIT: добавлен необязательный аргумент функции тестирования, по умолчанию - SameQ
.
EDIT: здесь приведена версия, которая описывает мой комментарий ниже и сообщает обо всех эквивалентах в группе, заданных функцией проектора, которая создает такое значение, что элементы списка считаются эквивалентными, если значение равно. Это, по существу, находит классы эквивалентности дольше заданного размера:
reportDuplicateClusters[list_List, projector_: (# &),
minimumClusterSize_: 2] :=
GatherBy[list, projector] //
Select[#, [email protected]# >= minimumClusterSize &] &
Вот пример, который проверяет пары целых чисел на их первые элементы, считая две пары эквивалентными, если их первые элементы равны
reportDuplicateClusters[RandomInteger[10, {10, 2}], #[[1]] &]
Ответ 6
Этот поток кажется старым, но я должен был решить это сам.
Это грубо, но делает ли это это?
Union[Select[Table[If[tt[[n]] == tt[[n + 1]], tt[[n]], ""], {n, Length[tt] - 1}], IntegerQ]]
Ответ 7
Учитывая список A,
получить не дублирующиеся значения в B
B = Удалить дубликаты [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 - ваш список. Я не знаю математики, поэтому синтаксис может быть или не быть совершенным здесь. Просто перейдите к документам на странице, с которой вы связались.