13
$\begingroup$

I just saw the function IndexBy in the autocomplete suggestions and I was curious to know exactly how it works. Unfortunately, there's no trace of it in the documentation. It returns Association objects, so it must be new (or recently refurbished) in version 10.0.2

What does this function do are what syntax does it require? Does it have further perks that are not immediately obvious?

Edit: As mentioned in the comments, as an undocumented function this was liable to be removed. And, indeed, it has been removed from version 10.1.0. The good thing is, if anyone needs a function like this, there's now kguler and Mr. Wizard's implementations to choose from.

$\endgroup$
5
  • 2
    $\begingroup$ if it is not documented, then it is not meant to be used at user level. It might be a place holder for future version. $\endgroup$
    – Nasser
    Commented Feb 20, 2015 at 12:40
  • $\begingroup$ Related answer $\endgroup$
    – m_goldberg
    Commented Feb 20, 2015 at 13:16
  • $\begingroup$ @Nasser If it is indeed not meant to be used at user level, I'm curious about why it shows up in the autocomplete suggestions. $\endgroup$ Commented Feb 20, 2015 at 15:35
  • $\begingroup$ @episanty, I think all system symbols will show up in the autocomplete suggestions, though many are undocumented. For a complete list of such symbols: Select[Names["*"],MatchQ[ToExpression[#<>"::usage"],_MessageName]&] (it takes a minute to run). $\endgroup$ Commented Feb 20, 2015 at 22:01
  • 3
    $\begingroup$ Note that IndexBy will be removed in a future version of Mathematica. It was something that was considered for 10.0.0 but didn't make the cut. $\endgroup$
    – Stefan R
    Commented Feb 26, 2015 at 17:37

2 Answers 2

10
$\begingroup$
?? *`*IndexBy*

enter image description here

Following the usual spelunking steps

ClearAttributes[IndexBy, {Protected, ReadProtected}]
?? IndexBy

reveals the code that defines IndexBy. Simplifying (and ignoring argument type-checks) it is something like:

indexBy[f_][expr_]:=Association[(f[#]->#)&/@If[AssociationQ[expr],Values[expr],expr]]

indexBy[foo][Range[5]]
(* <|foo[1]->1,foo[2]->2,foo[3]->3,foo[4]->4,foo[5]->5|> *)

indexBy[foo][<|a -> x, b -> y, c -> z|>]
(* <|foo[x]->x,foo[y]->y,foo[z]->z|> *)
$\endgroup$
11
$\begingroup$

Observing the code reported in kguler's answer I note that it could be written more efficiently, if such an operation is desired. Specifically (f[#]->#)& cannot be compiled because the result is a Rule. It would be better to map f directly to the values, then use AssociationThread to construct the association.

Proposal

indexBy[f_][expr_] := expr ~indexBy~ f

indexBy[asc_Association, f_] := Values[asc] ~indexBy~ f

p : indexBy[expr_, f_] /;
  ! AtomQ[expr] || Message[indexBy::normal, 1, HoldForm @ p] := 
    AssociationThread[f /@ expr, expr]

p : indexBy[_, _, __] /; 
  Message[indexBy::argt, indexBy, Length @ Unevaluated @ p, 1, 2] := Null

Timings

expr = Range[1*^6];
f = #^2 &;

IndexBy[expr, f] // AbsoluteTiming // First
indexBy[expr, f] // AbsoluteTiming // First
1.353077

0.404023
expr = AssociationThread @@ RandomReal[9, {2, 1*^6}];
f = Round;

IndexBy[expr, f] // AbsoluteTiming // First
indexBy[expr, f] // AbsoluteTiming // First
1.122064

0.372021
$\endgroup$
4
  • 1
    $\begingroup$ I just ran into this and had a question. On 10.1, the AtomQ version is placed above indexBy[expr_, f_] in the DownValues. So, that index[5, f] returns AssociationThread[5, 5]. This can be fixed by using indexBy[expr : Except[_?AtomQ, _], f_], but I'm not sure if that's the right thing to do. Any thoughts. $\endgroup$
    – rcollyer
    Commented Apr 20, 2015 at 19:45
  • 1
    $\begingroup$ @rcollyer I read your message before and thought "okay, when I get v10.1 I'll fix this" but now that I am running 10.1 I realize this has nothing to do with version and everything to do with a poorly conceived definition. Feel free to be more blunt about my stupid mistakes next time! $\endgroup$
    – Mr.Wizard
    Commented May 12, 2015 at 6:01
  • $\begingroup$ I didn't realize it was your mistake. I was just playing with it, broke it, and tried to fix it. Next time, do better. :D $\endgroup$
    – rcollyer
    Commented May 12, 2015 at 13:48
  • $\begingroup$ @rcollyer By the way what do you think of the || form in the answer now? It is my attempt at using Simon's flow control from (7820). Do you make use of such things yourself now? (You expressed interest below that post.) $\endgroup$
    – Mr.Wizard
    Commented May 12, 2015 at 15:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.