Подтвердить что ты не робот

Показать дубликаты в 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}, но дополнительный Союз [] решил бы это.)

Но не было ничего подобного (если бы я хорошо понимал все функции).

Итак, как это сделать?

4b9b3361

Ответ 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 - ваш список. Я не знаю математики, поэтому синтаксис может быть или не быть совершенным здесь. Просто перейдите к документам на странице, с которой вы связались.