Вопрос

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top