我需要构建一个部分Inverted Index
。类似的东西:
l = {{x, {h, a, b, c}}, {y, {c, d, e}}}
iI[l]
(*
-> {{a, {x}}, {b, {x}}, {c, {x, y}}, {d, {y}}, {e, {y}}, {h, {x}}}
*)
我认为它的作用非常清楚。在输入列表中,{x,y ...}是唯一的,而{a,b,c,..}则不是。输出应按#[[1]]
排序。
现在,我这样做:
iI[list_List] := {#, list[[Position[list, #][[All, 1]]]][[All, 1]]} & /@
(Union@Flatten@Last@Transpose@list)
但是对于这么简单的任务看起来太复杂了,似乎太慢了,我应该能够应付军团。
用于比较结果的试驾:
words = DictionaryLookup[];
abWords = DictionaryLookup["ab" ~~ ___];
l = {#, RandomChoice[abWords, RandomInteger[{1, 30}]]} & /@ words[[1 ;; 3000]];
First@Timing@iI[l]
(*
-> 5.312
*)
那么,有关加速的想法吗?
答案 0 :(得分:10)
似乎Reap
的一项经典任务 - Sow
(由于@Heike而在最终版本中有所改进):
iI[list_] := Sort[Reap[Sow @@@ list, _, List][[2]]]
然后,
iI[l]
{{a, {x}}, {b, {x}}, {c, {x, y}}, {d, {y}}, {e, {y}}, {h, {x}}}
和
In[22]:=
words=DictionaryLookup[];
abWords=DictionaryLookup["ab"~~___];
l={#,RandomChoice[abWords,RandomInteger[{1,30}]]}&/@words[[1;;3000]];
First@Timing@iI[l]
Out[25]= 0.047
修改强>
以下是具有类似(稍差)性能的替代版本:
iIAlt[list_] :=
Sort@Transpose[{#[[All, 1, 2]], #[[All, All, 1]]}] &@
GatherBy[Flatten[Thread /@ list, 1], Last];
有趣的是,Reap
- Sow
提供的解决方案比基于结构操作的解决方案更快。
编辑2
仅为了说明 - 对于那些喜欢基于规则的解决方案的人来说,这里有一个基于Dispatch
和ReplaceList
的组合:
iIAlt1[list_] :=
With[{disp = Dispatch@Flatten[Thread[Rule[#2, #]] & @@@ list]},
Map[{#, ReplaceList[#, disp]} &, Union @@ list[[All, 2]]]]
然而,它比其他两个慢约2-3倍。