5
$\begingroup$

I need to label some data in arbitrarily nested ragged lists, with a stream of unique labels. It's very convenient if the labels are consecutive integers, starting at 0 or 1, and if I can produce the same stream every time I label a given data set.

I can do this with recursive functions that thread around the current label in the parameter list and conventionally in every output (say the first element in a list, by convention; this is essentially an explicit simulation of the state monad of Haskell). It's cumbersome and ugly, so I'm looking for a better solution.

Unique comes close to fitting the bill. In a fresh kernel, MMA version 9.0.1 on Mac 10.8.4, consider the following

Table[Unique[],{3}] 

{$3, $4, $5}

Great. Let's try starting them at 1, following the documentation,

$ModuleNumber = 1; 
Table[Unique[], {3}]

{$6, $7, $8}

Ooops, surprise!

The following, which was my first attempt, produces an internal ENULL bugcheck

Block[{$ModuleNumber = 1},
 Table[Unique[], {3}]]

Mathematica has detected an internal error: vMessage ENULL

Please report this error as soon as possible to support@wolfram.com giving as many details as possible of the circumstances under which it occurred.

I can mimic the entire thing with my own global state variable and mimic of Unique, but thought I'd first check here for insight and advice.

$\endgroup$
  • 3
    $\begingroup$ I wouldn't play with $ModuleNumber in any case. Who knows what that may break. At the very least, you can break the uniqueness of variables produced by Module, and that can lead to all sort of bugs. $\endgroup$ – Leonid Shifrin Jun 26 '13 at 19:35
  • 1
    $\begingroup$ I understand the warning (and basically agree with it, outside of toys, and I was making a toy). It is interesting that the documentation explicitly states that $ModuleNumber can be reset, even outside a Block. But then, it doesn't actually work :) $\endgroup$ – Reb.Cabin Jun 26 '13 at 19:38
  • $\begingroup$ Perhaps, redefining $ModuleNumber may have some constructuve uses which I am unaware of. But personally I would not mess with it. $\endgroup$ – Leonid Shifrin Jun 26 '13 at 19:47
6
$\begingroup$

I would use this solution:

newStream[start_: 1] := Module[{i = start}, i++ &]

s = newStream[];
Table[s[], {5}]
(* Out: {1, 2, 3, 4, 5} *)

s = newStream[20];
Table[s[], {5}]
(* Out: {20, 21, 22, 23, 24} *)

This avoids having a global variable, and you can have many streams at the same time.

| improve this answer | |
$\endgroup$
2
$\begingroup$

Maybe something along those lines?

nextlabel[] := StringTemplate["`` label"][++lastlabel]



lastlabel = 0;
Table[ nextlabel[], {10} ]
{"1 label", "2 label", "3 label", "4 label", "5 label", "6 label", 
"7 label", "8 label", "9 label", "10 label"} 
| improve this answer | |
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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