# Modify BinLists to give elements indices in list instead of giving the list elements belonging to each bin

How could I use BinLists to give elements indices in list instead of giving the list elements belonging to each bin ?

Thanks.

using the 2d form of BinLists ( note the first dimension binspec is cooked up so there is just one bin )

 list = RandomReal[{0, 1}, {20}];
binspec = {0, 1, .1};
(#[[All, 1]] & /@ First@BinLists[ MapIndexed[{First@#2, #} &, #] ,
{0, Length@# + 1, Length@# + 1}, binspec]) &@list


{{1, 10, 20}, {6}, {7, 15}, {4}, {5, 12, 17}, {11}, {14, 18}, {9}, {2, 3, 8, 16, 19}, {13}}

 ( list[[#]] & /@ % ) == BinLists[ list , binspec]


True

You could simply do this as well:

 Union@Flatten@(Position[ list, #]  & /@ # ) & /@ BinLists[list, binspec]

• Thanks for this black magic.. unreadable, but apparently it works! ;) – Thomas Fankhauser Apr 19 '15 at 11:36

For my own question and self-answer I wrote the following utility function.

BinPositions[vals_, brakes_, sameTest_] :=
Map[val \[Function]
Catch@Module[{lo = 1, mid, hi = Length[brakes], el, res},
While[lo <= hi, Which[
TrueQ@sameTest[val, el = brakes[[mid = Floor[(lo + hi)/2]]]],
Throw[mid],
el > val, hi = mid - 1,
True, lo = mid + 1]];
lo - 1/2],
vals]


The semanthic is sligtly different from previous answer, but, maybe, it can be adapted to your scenario.

list = RandomReal[{0, 100}, {20}]
brakes = Union@RandomInteger[{0, 100}, 10]
Floor@BinPositions[list, brakes, SameQ]


{48.311, 40.7217, 50.8321, 73.2729, 24.7769, 42.4868, 12.475, 7.04288, 3.22704, 89.9731, 82.0066, 73.565, 83.0642, 45.4985, 81.3878, 55.5902, 82.3677, 68.8531, 57.4473, 83.1311}

{6, 20, 28, 32, 35, 52, 73, 82, 95}

{5, 5, 5, 7, 2, 5, 1, 1, 0, 8, 8, 7, 8, 5, 7, 6, 8, 6, 6, 8}

Using the function positionDuplicates from this answer by @Szabolcs

ClearAll[positionDuplicates, dispatchF, positionBins]
positionDuplicates[list_] :=  GatherBy[Range@Length[list], list[[#]] &];

dispatchF = Dispatch @ Thread[DeleteDuplicates[#] -> positionDuplicates[#]] &;
positionBins = Union @@@ (BinLists[#, #2] /. dispatchF[#1]) &;


Example 1:

data = RandomInteger[5, 17]


{5, 4, 1, 3, 0, 3, 0, 0, 5, 5, 0, 0, 5, 1, 5, 5, 0}

BinLists[data, 3] (* change 3 to your choice of binspecs *)


{{}, {1, 0, 0, 0, 0, 0, 1, 0}, {5, 4, 3, 3, 5, 5, 5, 5, 5}}

positionBins[data, 3]


{{}, {3, 5, 7, 8, 11, 12, 14, 17}, {1, 2, 4, 6, 9, 10, 13, 15, 16}}

Example 2:

BinLists[data, {{0, 2, 4, 6}}]


{{1, 0, 0, 0, 0, 0, 1, 0}, {3, 3}, {5, 4, 5, 5, 5, 5, 5}}

positionBins[data, {{0, 2, 4, 6}}]


{{3, 5, 7, 8, 11, 12, 14, 17}, {4, 6}, {1, 2, 9, 10, 13, 15, 16}}