Re: Better way to write this
- To: mathgroup at smc.vnet.net
- Subject: [mg85085] Re: Better way to write this
- From: Szabolcs Horvát <szhorvat at gmail.com>
- Date: Sun, 27 Jan 2008 05:50:16 -0500 (EST)
- Organization: University of Bergen
- References: <fnet45$id5$1@smc.vnet.net>
Louis Theran wrote: > I have the following function that takes as its input a number of > lists and returns the elements in each of them that appear exactly > once: > > SpecialElements[lists:_List..]:= > Module[{l,n,Sower,Reaper}, > l = {lists}; n = Length[l]; > Sower[l_,{idx_}]:= Sow[idx,{#}] & /@ l; > Reaper[val_,{place_}] := Sow[val,place]; > Reaper[val_,x_]:= Null; > Reap[Reap[MapIndexed[Sower, l],_,Reaper],Range[n]][[2]]] > > This works pretty well, but since I am using it on rather large > inputs, I was wondering if there is a faster way to implement it than > Reap/Sow, which is sort of counting in unary. > Dear Louis, If sorting the lists is not a problem, the following function will probably be faster than the Sow/Reap version in most cases: specElem[lists__List] := With[ {spec = Cases[Tally@Join[lists], {el_, 1} :> el]}, Intersection[spec, #] & /@ {lists} ] In[9]:= ll = RandomInteger[50000, {5, 50000}]; In[10]:= Timing[a = specElem @@ ll;] Out[10]= {0.437, Null} In[11]:= Timing[b = SpecialElements @@ ll;] Out[11]= {7.734, Null} In[12]:= a === (Sort@First[#] & /@ b) Out[12]= True In reality the performance can be very dependent on the input data: the number of input lists, and the number of different elements present in the lists compared to the length of the lists. Szabolcs