Prompted by comments conversation with Mr. Wizard, a routine I use:
findMultiPosXX[list_, find_, allowBits_: False, skipCands_: True] :=
Module[{f = DeleteDuplicates[find], o, l, oo, bitmax = 20, cands, dims},
If[allowBits && Length@f <= bitmax,
With[{r = If[Length@(dims = Dimensions@list) == 1, Range@Length@list,
Array[List, dims]]}, Pick[r, BitXor[list, #], 0] & /@ f],
If[skipCands,
(* This is the core explained below *)
(l = Length@f;
oo = Ordering[o = Ordering[Join[f, list, f]]];
Inner[o[[# ;; #2]] &, oo[[;; l]], oo[[-l ;;]], List][[All, 2 ;; -2]] - l),
(* end of core method *)
(cands =
SparseArray[
BitAnd[UnitStep[list - Min@f], UnitStep[Max@f - list]]]["NonzeroPositions"];
cands[[#]] & /@ (l = Length@f;
oo = Ordering[o = Ordering[Join[f, Extract[list, cands], f]]];
Inner[o[[# ;; #2]] &, oo[[;; l]], oo[[-l ;;]], List][[All, 2 ;; -2]] - l))]]];
Use:
test = RandomInteger[10, 20]
findMultiPosXX[test, {5, 10, 8}]
(*
{10, 0, 1, 4, 10, 5, 7, 2, 7, 7, 1, 4, 9, 3, 3, 7, 7, 8, 2, 5}
{{6, 20}, {1, 5}, {18}}
*)
With default argument (just the target and searches), can beat GatherBy by order of magnitude, and Position with Alternatives (which leaves you with only positions but no mapping to values) by a factor of 5 or more.
When searching for scalar values at the top level, setting the third argument to True will use bit-map search for 20 or fewer search terms, upping the performance typically by 4-10X. Also for scalar searches, if one knows the search space spans a small range of the data range, setting the fourth argument to False causes the search space to be narrowed, boosting performance from 2X to over an order of magnitude.
E.g., testing against several of the answers and Position with Alternatives, using the OP specified sizes with test = RandomInteger[1000000, {60000, 3}] and
finds = RandomSample[test, 1200], the speed advantage results expressed as time/mytime were {7.4286, 6.1429, 20.857, 21.143, 419.71}.
An explanation of the core method (when no optional arguments are set):
Let's take an example list:
test = RandomInteger[5, 20]
(* {5, 3, 2, 5, 0, 4, 3, 4, 4, 0, 0, 5, 4, 0, 5, 5, 5, 4, 0, 2} *)
Say we want to look for threes and fives. We'll call that lookfor, and prepend/append that to the target list:
lookfor = {3, 5}
work = Join[lookfor, test, lookfor]
(*
{3, 5}
{3, 5, 5, 3, 2, 5, 0, 4, 3, 4, 4, 0, 0, 5, 4, 0, 5, 5, 5, 4, 0, 2, 3,5}
*)
Now, let's use Ordering to get the positions from work in its sorted incarnation, along with the ordering of that order. That is just the permutation of the range of the length of work by a permutation list of the order (you can do it that way, but somewhat surprisingly, using Ordering on an order is faster):
Column[{order = Ordering[work],orderOforder = Ordering[order]}, Left, 2]
(*
{7,12,13,16,21,5,22,1,4,9,23,8,10,11,15,20,2,3,6,14,17,18,19,24}
{8,17,18,9,6,19,1,12,10,13,14,2,3,20,15,4,21,22,23,16,5,7,11,24}
*)
Now, here's the "magic". Take note of the first and last two entries of the permutation (two being the length of our lookfor list):
lengthOflookfor = Length@lookfor;
transposed = Transpose[{orderOforder[[;; lengthOflookfor]],
orderOforder[[-lengthOflookfor ;;]]}]
(* {{8, 11}, {17, 24}} *)
These pairs are in essence nothing more than spans, corresponding to the positions, for each of our lookfor elements, in the first ordering, mapping us the corresponding position(s) if any in the work list:
Column[{span = Span @@@ transposed, places = order[[#]] & /@ span,
work[[#]] & /@ places}, Left, 2]
(*
{8;;11,17;;24}
{{1,4,9,23},{2,3,6,14,17,18,19,24}}
{{3,3,3,3},{5,5,5,5,5,5,5,5}}
*)
So we see that following the order from positions 8 to 11 and 17 to 24, we recover the positions of the elements we're interested in from the work list.
All that's left to do is to trim our padded element entries from the result and adjust the positions to get the actual positions from the original list:
Column[{recovered = ArrayPad[#, -1] & /@ places - lengthOflookfor,
test[[#]] & /@ recovered}, Left, 2]
(*
{{2,7},{1,4,12,15,16,17}}
{{3,3},{5,5,5,5,5,5}}
*)
Because Ordering is, in general, very fast, this trick allows us to recover the positions of a large subset of elements (or show non-existence) from the target list very quickly.
Position(which is very slow)? It's the same and should be very fast. Even if you need to constructsmallList, you can use these randomly generated positions and extract the elements usingPart, which would still be faster. Also, your pure function construction inMapis incorrect... – rm -rf Mar 22 '13 at 06:21bigList = RandomInteger[{1, 255}, {60000, 3}]; smallList = RandomChoice[bigList, 1200];try to decrease :First[Timing[Flatten[Map[Position[bigList, #] &, smallList]]]]. If the OP confirms this is what he wants, I can do it myself. – andre314 Mar 22 '13 at 08:06sublistshave different values,but structure was unique like {{x1,y1,z1},{x2,y2,z2},....}. – subbu Mar 22 '13 at 09:58bigList=RandomInteger[...];...) doesn't work – andre314 Mar 22 '13 at 10:15Length[Union[bigList]]with bigList your own list, not that of the guys below? – Sjoerd C. de Vries Mar 22 '13 at 13:26Length[bigList]as well. – Sjoerd C. de Vries Mar 22 '13 at 13:53Unique, butUnion. – Sjoerd C. de Vries Mar 22 '13 at 14:15