2011-10-13 13 views
10

Ho bisogno di costruire un parziale Inverted Index. Qualcosa di simile:Edificio ad indice parziale parzialmente invertito

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}}} 
*) 

Penso che sia abbastanza chiaro cosa fa. Nell'elenco di input, {x, y ...} sono unici, mentre {a, b, c, ..} non lo sono. L'uscita dovrebbe essere ordinata per #[[1]].

In questo momento, sto facendo questo:

iI[list_List] := {#, list[[Position[list, #][[All, 1]]]][[All, 1]]} & /@ 
        ([email protected]@[email protected]@list) 

ma sembra troppo complicata per un compito così facile, sembra troppo lento, e dovrei essere in grado di far fronte con Legion.

un test drive per confrontare i risultati:

words = DictionaryLookup[]; 
abWords = DictionaryLookup["ab" ~~ ___]; 
l = {#, RandomChoice[abWords, RandomInteger[{1, 30}]]} & /@ words[[1 ;; 3000]]; 
[email protected]@iI[l] 
(* 
-> 5.312 
*) 

Quindi, tutte le idee per un aumento di velocità?

risposta

10

Sembra un compito classico per Reap-Sow (miglioramento nella versione finale a causa di @Heike):

iI[list_] := Sort[Reap[Sow @@@ list, _, List][[2]]] 

Poi,

iI[l] 

{{a, {x}}, {b, {x}}, {c, {x, y}}, {d, {y}}, {e, {y}}, {h, {x}}} 

e

In[22]:= 
words=DictionaryLookup[]; 
abWords=DictionaryLookup["ab"~~___]; 
l={#,RandomChoice[abWords,RandomInteger[{1,30}]]}&/@words[[1;;3000]]; 
[email protected]@iI[l] 
Out[25]= 0.047 

EDIT

Ecco una versione alternativa con un simile (leggermente peggiore) prestazioni:

iIAlt[list_] := 
    [email protected][{#[[All, 1, 2]], #[[All, All, 1]]}] &@ 
      GatherBy[Flatten[Thread /@ list, 1], Last]; 

E 'interessante che Reap-Sow qui dà una soluzione ancora leggermente più veloce rispetto a quella basata su azioni strutturali.

EDIT 2

Solo per un'illustrazione - per chi preferisce le soluzioni basate su regole, qui è una basata su una combinazione di Dispatch e ReplaceList:

iIAlt1[list_] := 
    With[{disp = [email protected][Thread[Rule[#2, #]] & @@@ list]}, 
     Map[{#, ReplaceList[#, disp]} &, Union @@ list[[All, 2]]]] 

Si tratta di circa 2- 3 volte più lento degli altri due, però.

+1

Un passo verso la gloria http://i.stack.imgur.com/EqlqO.png :) –

+2

Davvero bello. 'La discussione dell'elenco non è nemmeno necessaria; potresti fare qualcosa come 'iI [list_]: = Ordina [Reap [Sow @@@list, _, List] [[2]]] per renderlo ancora più veloce. – Heike

+0

@Heike Effettivamente, grazie. Quando stavo sviluppando il codice, in qualche modo pensavo che dovesse essere "Sow [# 2, # 1] &", che, se fosse vero, richiedeva "Thread". Quando ho capito che l'ordine è diretto, ho dimenticato di rimuoverlo. Modifica per utilizzare la tua versione. –