Ответ 1
Вы хотите DeleteDuplicates
, который сохраняет порядок списка:
In[13]:= DeleteDuplicates[{.8, .3, .8, .5, .3, .6}]
Out[13]= {0.8, 0.3, 0.5, 0.6}
Он был добавлен в Mathematica 7.0.
Я создаю плоские списки с 10 ^ 6 до 10 ^ 7 Реальные числа, а некоторые из них повторяются.
Мне нужно удалить повторяющиеся экземпляры, сохраняя только первое вхождение и не изменяя порядок списка.
Ключ здесь - эффективность, так как у меня много списков для обработки.
Пример (подделка):
Вход:
{.8, .3 , .8, .5, .3, .6}
Желаемый выход
{.8, .3, .5, .6}
Кроме примечания
Удаление повторяющихся элементов с помощью Union (без сохранения порядка) дает в моем бедном ноутбуке:
DiscretePlot[a = RandomReal[10, i]; [email protected]@[email protected], {i, 10^6 [email protected]}]
Вы хотите DeleteDuplicates
, который сохраняет порядок списка:
In[13]:= DeleteDuplicates[{.8, .3, .8, .5, .3, .6}]
Out[13]= {0.8, 0.3, 0.5, 0.6}
Он был добавлен в Mathematica 7.0.
Не конкурировать с другими ответами, но я просто не мог помочь использовать решение Compile
. Решение основано на построении двоичного дерева поиска, а затем проверке каждого числа в списке, является ли его индекс в списке тем, который используется при построении b-дерева. Если да, это исходный номер, если нет - это дубликат. Что делает это решение интересным для меня, так это то, что он показывает способ эмуляции "pass-by-reference" с помощью Compile
. Дело в том, что если мы встроили компилируемые функции в другие функции Compiled (и это может быть достигнуто с помощью опции "InlineCompiledFunctions" ), мы можем ссылаться во внутренних функциях на переменные, определенные в области внешней функции (из-за того, что работает inlining), Это не настоящая передача по ссылке, но она по-прежнему позволяет комбинировать функции с меньшими блоками, без снижения эффективности (это больше в духе макроэкспонирования). Я не думаю, что это задокументировано и не имеет понятия, останется ли это в будущих версиях. В любом случае, вот код:
(* A function to build a binary tree *)
Block[{leftchildren , rightchildren},
makeBSearchTree =
Compile[{{lst, _Real, 1}},
Module[{len = Length[lst], ctr = 1, currentRoot = 1},
leftchildren = rightchildren = Table[0, {Length[lst]}];
For[ctr = 1, ctr <= len, ctr++,
For[currentRoot = 1, lst[[ctr]] != lst[[currentRoot]],(*
nothing *),
If[lst[[ctr]] < lst[[currentRoot]],
If[leftchildren[[currentRoot]] == 0,
leftchildren[[currentRoot]] = ctr;
Break[],
(* else *)
currentRoot = leftchildren[[currentRoot]] ],
(* else *)
If[rightchildren[[currentRoot]] == 0,
rightchildren[[currentRoot]] = ctr;
Break[],
(* else *)
currentRoot = rightchildren[[currentRoot]]]]]];
], {{leftchildren, _Integer, 1}, {rightchildren, _Integer, 1}},
CompilationTarget -> "C", "RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True}]];
(* A function to query the binary tree and check for a duplicate *)
Block[{leftchildren , rightchildren, lst},
isDuplicate =
Compile[{{index, _Integer}},
Module[{currentRoot = 1, result = True},
While[True,
Which[
lst[[index]] == lst[[currentRoot]],
result = index != currentRoot;
Break[],
lst[[index]] < lst[[currentRoot]],
currentRoot = leftchildren[[currentRoot]],
True,
currentRoot = rightchildren[[currentRoot]]
]];
result
],
{{leftchildren, _Integer, 1}, {rightchildren, _Integer,
1}, {lst, _Real, 1}},
CompilationTarget -> "C", "RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True}
]];
(* The main function *)
Clear[deldup];
deldup =
Compile[{{lst, _Real, 1}},
Module[{len = Length[lst], leftchildren , rightchildren ,
nodup = Table[0., {Length[lst]}], ndctr = 0, ctr = 1},
makeBSearchTree[lst];
For[ctr = 1, ctr <= len, ctr++,
If[! isDuplicate [ctr],
++ndctr;
nodup[[ndctr]] = lst[[ctr]]
]];
Take[nodup, ndctr]], CompilationTarget -> "C",
"RuntimeOptions" -> "Speed",
CompilationOptions -> {"ExpressionOptimization" -> True,
"InlineCompiledFunctions" -> True,
"InlineExternalDefinitions" -> True}];
Вот несколько тестов:
In[61]:= intTst = [email protected][{0,500000},1000000];
In[62]:= (res1 = deldup[intTst ])//Short//Timing
Out[62]= {1.141,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}}
In[63]:= (res2 = Tally[intTst,Equal][[All,1]])//Short//Timing
Out[63]= {0.64,{260172.,421188.,487754.,259397.,<<432546>>,154340.,295707.,197588.,119996.}}
In[64]:= res1==res2
Out[64]= True
Не так быстро, как версия Tally
, но также и Equal
, и, как я уже сказал, моя задача состояла в том, чтобы проиллюстрировать интересную технику (IMO).
Для версий Mathematica до 7 и для общих интересов здесь есть несколько способов реализации функции UnsortedUnion (т.е. DeleteDuplicates). Они собираются из справочных документов и MathGroup. Они были скорректированы для приема нескольких списков, которые затем соединены по аналогии с Союзом.
Для Mathematica 4 или ранее
UnsortedUnion = Module[{f}, f[y_] := (f[y] = Sequence[]; y); f /@ [email protected]##] &
Для Mathematica 5
UnsortedUnion[x__List] := Reap[Sow[1, [email protected]], _, # &][[2]]
Для Mathematica 6
UnsortedUnion[x__List] := Tally[[email protected]][[All, 1]]
От Леонида Шифрина для Mathematica 3+ (?)
unsortedUnion[x_List] := Extract[x, Sort[Union[x] /. Dispatch[MapIndexed[Rule, x]]]]