• tagno25 (unregistered) in reply to Charleh
    Charleh:
    Anonymous:
    Steve Johnstone:
    I would love to know what those requirements are for. Any solution that involves generating a random number has a chance of being wrong because true randomness can and will generate sequential numbers.
    Bear in mind that the requirements said nothing about the IDs being random. It was the idiot coder who decided that was a good idea, it certainly never came from the requirements.

    Can you have a non-random set of numbers that's not a sequence?

    use the digits of PI, it will seem totally random
  • (cs) in reply to the beholder
    the beholder:
    Jellineck:
    Medezark:
    You would run out of unique identifiers after a few periods.
    I've found that you can run out of unique identifiers after a number of missed periods.
    When my wife missed her periods we had to start thinking on an identifier. It didn't have to be unique, though.
    In fact non unique identifiers has an advantage. You only have to pay for one of them to go to college and they can both use the same diploma.
  • STarLite (unregistered)
    int getRandomNumber(){
      return 4; // Chosen by fair dice roll
                //guaranteed to be random
    }
    

    http://xkcd.com/221/

  • tagno25 (unregistered) in reply to STarLite
    STarLite:
    int getRandomNumber(){
      return 4; // Chosen by fair dice roll
                //guaranteed to be random
    }
    
    http://xkcd.com/221/
    you would need to roll a d100 or two d10s
  • B (unregistered) in reply to JR
    JR:
    static int lastGeneratedCode = 0; final int MAX_NUM_ACTIVITIES = 48;

    public string GenerateNewActivityCode(Period period) { lastGeneratedCode+=2; return ... ; // add your favorite string conversion here }

    Am I missing something? Non-sequential? Yes, the odd numbers are missing. Uniqueness? Of course.

    Any number in a sequence is ... sequential, so I'd say the solution method's body should be throw new StupidRequirementException();

  • Guardian Bob (unregistered) in reply to JR

    Apparently people don't understand what a sequence is. http://en.wikipedia.org/wiki/Sequence

    It is called the Fibonacci sequence, and that certainly isn't i++.

    Also, did anyone note, 99 would never be valid (due to Random.Next being max exclusive).

    While the 3 tries is a little strange, using a random number seems to be a valid way to go.

    If you expect approximately half the space to be used in some cases, well I wouldn't use an approach that would take longer as more items are added.

  • Mean Mr. Mustard (unregistered)

    Obviously the coder has never explored any card games. This cries out for a card deck shuffle algorithm - essentially each Period should be given a shuffled deck of 48 unique cards (picked from a deck of 99 cards); then assigning identifiers would merely be dealing off the top of the deck.

    Doubling down would be optional, of course.

  • Anon (unregistered) in reply to wds
    wds:
    TFA says:
    ...and each Activity within a Period should have a unique, non-sequential, two-digit identifier (e.g. 02, 41, 99).
    You assumed that this meant unique within a period. It doesn't really say that though. If it said what you think it said it should say "each Activity should have a unique ... identifier within a Period". I agree that it's probably meant to say that, but TRWTF is, as always, the requirements.

    Yes, I assumed that meant unique within a period. I assumed that because that's what it actually says. I assume what the words said and what was actually wanted are in agreement.

  • Peer (unregistered) in reply to Guardian Bob
    Guardian Bob:
    Apparently people don't understand what a sequence is. http://en.wikipedia.org/wiki/Sequence

    It is called the Fibonacci sequence, and that certainly isn't i++.

    Also, did anyone note, 99 would never be valid (due to Random.Next being max exclusive).

    While the 3 tries is a little strange, using a random number seems to be a valid way to go.

    If you expect approximately half the space to be used in some cases, well I wouldn't use an approach that would take longer as more items are added.

    Except that the random number thing doesn't work particularly well. Even with 4 random draws for each new ID in a period, there is a probability of about 22% that generating a new ID will fail on or before the 20th new ID in that period (with 1 random draw that would be 87%). That doesn't seem particularly valid.

  • ipeet (unregistered) in reply to Guardian Bob
    Guardian Bob:
    Apparently people don't understand what a sequence is. http://en.wikipedia.org/wiki/Sequence

    ...

    While the 3 tries is a little strange, using a random number seems to be a valid way to go.

    If you expect approximately half the space to be used in some cases, well I wouldn't use an approach that would take longer as more items are added.

    Apparently people don't understand The Birthday Problem. http://en.wikipedia.org/wiki/Birthday_problem

    You can't just use a random number blindly, or you will have collisions, which will cause interesting things to happen if the random number happens to be an identifying index. This is what makes hash tables interesting.

    Random numbers are a good way to go, but you need some way to check for collision. For a small dataset, you can just use a lookup table. For a large dataset, where the memory cost of the lookup table is prohibitive, you can use a sorted list, or a hashtable, or etc... to reduce the complexity of lookup. As the article implies, there are plenty of valid solutions. This just isn't one of them.

  • (cs)

    Even before this method begins returning non-unique codes, it fails when returning codes < 10. ToString() doesn't automatically supply the leading 0.

  • lomendil (unregistered)

    The requirements don't say what many people seem to think they say. if you add 5 activities to an empty period, 1-5 is fine. Then you remove 3. On some definition, there's your non-sequential. With a lot of adding and deleting, you can even get non-monotonic sequences.

    The job is not to produce 48 numbers that aren't in order. It is to deal with up to 48 that might not be.

  • bob (unregistered) in reply to frits
    frits:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    Maybe someone should explain the concept to you.

    Maybe someone should have explained the concept of IUDs to your mom.

  • bl@h (unregistered)
    Anon:
    the beholder:
    Jellineck:
    Medezark:
    You would run out of unique identifiers after a few periods.
    I've found that you can run out of unique identifiers after a number of missed periods.
    When my wife missed her periods we had to start thinking on an identifier. It didn't have to be unique, though.

    Indeed. Just ask George Foreman (and 5 of his 10 children who are also called George Foreman).

    Maybe his seed wasn't randomly generated?

  • LeGEC (unregistered)

    I'm still trying to figure out what a non-sequential identifier is. Is "42" non-sequential ? Or "01" ? What about "34" ?

  • F (unregistered) in reply to That Guy
    That Guy:
    I think those of you focusing on a list of 48 potential numbers are missing the fact that Periods may have up to 100 activities.

    If you take the trouble to read it, you will find that what it actually says is "A Period can have anywhere from zero to forty eight Activities ...". Assuming you can read, that is, which may be the problem.

  • OldCoder (unregistered) in reply to Medezark
    Medezark:
    The real WTF is the requirement for a "unique non-sequential 2 digit identifier", Unless the Activity identifier only has to be unique within a specific period, and even then it's a little odd.

    You would run out of unique identifiers after a few periods.

    So many ways to do this. And all of them wrong.

    It reminds me of the "randomly assign jobs" code we've been asked to implement. I'll do a full write up later.

    You might even try reading the spec! This says nothing about generating numbers. All it's saying is that, in any period (e.g. a college teaching period) up to 48 activities may take place selected from a list of 100. The program has to ensure that the selected task numbers chosen (average three) are unique for each period. No random numbers, no unique identifiers, nothing like that at all.

  • (cs) in reply to bob
    bob:
    frits:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    Maybe someone should explain the concept to you.

    Maybe someone should have explained the concept of IUDs to your mom.

    Cool. Is it old joke time? What do you call a person with no arms and no legs in the ocean?

  • F (unregistered) in reply to Steve
    Steve:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    You might want to read up on that concept for yourself. You do realise that there is no such thing as a two digit UUID, don't you?

    You just need to apply a little data compression.

  • (cs)

    I bet there were a max of 3 activities in a period when this function was written. The requirement changed, but the function never changed.

  • Plz Send Me The Code (unregistered) in reply to frits
    frits:
    bob:
    frits:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    Maybe someone should explain the concept to you.

    Maybe someone should have explained the concept of IUDs to your mom.

    Cool. Is it old joke time? What do you call a person with no arms and no legs in the ocean?

    I'm envious...that's so awesome.

  • (cs) in reply to Steve
    Steve:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    You might want to read up on that concept for yourself. You do realise that there is no such thing as a two digit UUID, don't you?

    Well, there are. But there are only 100 of them (or 90, if you don't count 05 as two-digit).

    I use the number 11 by the way.

  • Anonymous (unregistered)

    Everyone's arguing about the definition of a sequence but I think it is fair to infer that when the requirements said "non-sequential" they actually meant "non-linear". It can be argued that all numbers are sequential according to some sequence so clearly the intention of the requirements was to ensure that it was not a linear sequence, as in i = i + 1.

    So TRWTF is the requirements spec, as always. But I think it is fair for us to get over the "non-sequential" bit and take it that they meant "non-linear".

  • Anonymous (unregistered) in reply to Abdiel
    Abdiel:
    Steve:
    bob:
    64th

    Maybe somebody tried to explain the concept of UUIDs to him.

    You might want to read up on that concept for yourself. You do realise that there is no such thing as a two digit UUID, don't you?

    Well, there are. But there are only 100 of them (or 90, if you don't count 05 as two-digit).

    I use the number 11 by the way.

    Hey, that's my two digit UUID as well! Are you trying to tell me my UUID is not universally unique?! I'm using it in production and everything, what a mess...!

  • noland (unregistered) in reply to JR

    [quote user="JR"]static int lastGeneratedCode = 0; final int MAX_NUM_ACTIVITIES = 48;

    public string GenerateNewActivityCode(Period period) { lastGeneratedCode+=2; return ... ; // add your favorite string conversion here }

    Am I missing something? Non-sequential? Yes, the odd numbers are missing. Uniqueness? Of course.[/quote]

    Yes, you missed "(e.g. 02, 41, 99)" - from the specs.

    quote user="This would make a good Perl golf question"]Here we go

    [code]$id=sprintf('%02d',(1..48)[int(rand(47))+1]);[code] [/quote]

    [code]$id=sprintf('%02d',rand(98)+1);[code] Eagle!

  • Anonymous (unregistered) in reply to Salami
    Salami:
    I bet there were a max of 3 activities in a period when this function was written. The requirement changed, but the function never changed.
    The article made a point of mentioning that there were normally three activities, so you're probably right. However, it doesn't really excuse the naïve implementation - it would have been a poor solution even when there were just three activities.
  • asdf (unregistered) in reply to Anonymous

    [quote user="Anonymous"]Everyone's arguing about the definition of a sequence but I think it is fair to infer that when the requirements said "non-sequential" they actually meant "non-linear"...]

    Nonlinear means an equation whose terms are higher than the first degree [ax^2 + bx + c]. Sequential means consecutive. Non-sequential=non-consecutive. Non-sequential<>nonlinear. The definition of 'sequence' has nothing to do with the requirement. The definition of 'sequential' does.

  • AnOldRelic (unregistered) in reply to Mean Mr. Mustard
    Mean Mr. Mustard:
    Doubling down would be optional, of course.
    I think that the chicken-y, cheesy, bacony goodness should be mandatory.
  • (cs)

    As long as there are no problems with maintaining state, here's how I'd do it. It won't win a code golf contest, but it's pretty easy to read and understand, even if you don't know Delphi:

    unit RandomSequence;
    
    interface
    uses
      Generics.Collections;
    
    type
      TRandomSequence = class
      private
        FList: TList<integer>;
        FCounter: integer;
        function GetMax: integer;
      public
        constructor Create(max, count: integer);
        destructor Destroy; override;
        function Next: string;
        property Counter: integer read FCounter;
        property Max: integer read GetMax;
      end;
    
    implementation
    uses
      SysUtils;
    
    { TRandomSequence }
    
    constructor TRandomSequence.Create(max, count: integer);
    var
      i: Integer;
    begin
      assert(count <= max);
      FList := TList<integer>.Create;
      //fill
      for i := 0 to max do
        FList.Add(i);
      //shuffle
      for i := 0 to max do
        FList.Exchange(i, Random(max + 1));
      //truncate
      FList.Count := count;
    end;
    
    destructor TRandomSequence.Destroy;
    begin
      FList.Free;
      inherited;
    end;
    
    function TRandomSequence.GetMax: integer;
    begin
      result := FList.Count - 1;
    end;
    
    function TRandomSequence.Next: string;
    begin
      if FCounter >= FList.Count then
        raise Exception.Create('Out of numbers!');
      result := format('%.2d', [FList[FCounter]]);
      inc(FCounter);
    end;
    
    end.
  • (cs) in reply to Anon
    Anon:
    the beholder:
    Jellineck:
    Medezark:
    You would run out of unique identifiers after a few periods.
    I've found that you can run out of unique identifiers after a number of missed periods.
    When my wife missed her periods we had to start thinking on an identifier. It didn't have to be unique, though.

    Indeed. Just ask George Foreman (and 5 of his 10 children who are also called George Foreman).

    Also, in various parts of South America, it's not unusual for a family to have more than one daughter whose first name is Maria. They'll often go by their middle names.

  • usitas (unregistered)

    Clearly what is needed is a web service to generate the random numbers for you by passing in an XML document containing all the numbers previously used, then have the web service call itself recursively until the new, unique numbers are chosen.

    I would have thought this was obvious.

  • (cs) in reply to STarLite

    TRWTF is the shockingly high percentage of programmers that can't read and understand these very simple requirements.

    This is truly scary. The requirements were very simple, and pretty straightforward. Some people have been adding in their own requirements (must be random numbers), or flat out misinterpreting (100 events when the requirements say 48). And what is up with people questioning whether the identifier is supposed to be unique to a given period? Its pretty clear and obvious that was the intent of the requirement. Lets just slow the entire development process down with even more pedantic questions about things that are clear to anyone with half a brain. Thats the BSA and PMs jobs, not programmers!

  • (cs) in reply to TGVish
    TGVish:
    So the risk of generating 4 an ids already in use is 1/4*1/4*1/4*1/4=1/256 or something like 0.3%

    Or did I miss something.

    The probability that two people in a group share the same birthday is 50% when there are more than 23 people, and that's with 365 numbers to chose from. So yes, you did miss something, like probability 101.

    Take the worst case scenario: 47 out of 100 numbers have been taken. Then random guess #1 has a probability of failing of 47/100, #2 as well, #3 as well and #4 as well. The chance that they all fail is therefore (47/100)^4 = 5%. And that is assuming the random generator doesn't get reset...

    But that's the same math I did, but I did not use the worst case senario because the bug repports said it would happend around 25 periods. Which give (25/100)^4=0.3%

  • Hatterson (unregistered) in reply to tiller
    tiller:
    TGVish:
    So the risk of generating 4 an ids already in use is 1/4*1/4*1/4*1/4=1/256 or something like 0.3%

    Or did I miss something.

    The probability that two people in a group share the same birthday is 50% when there are more than 23 people, and that's with 365 numbers to chose from. So yes, you did miss something, like probability 101.

    Take the worst case scenario: 47 out of 100 numbers have been taken. Then random guess #1 has a probability of failing of 47/100, #2 as well, #3 as well and #4 as well. The chance that they all fail is therefore (47/100)^4 = 5%. And that is assuming the random generator doesn't get reset...

    But that's the same math I did, but I did not use the worst case senario because the bug repports said it would happend around 25 periods. Which give (25/100)^4=0.3%

    That's the probability it fails on exactly the 25th run. The probability it fails then or before then is much higher.

  • A Gould (unregistered) in reply to DocBrown
    DocBrown:
    TRWTF is.. Why non-sequential?

    Probably to reduce user-error (someone typing 04 instead of 05 and coding to the wrong activity).

    Our old system ran 3-3-13 (1,4,7,20,23,26,39...), which in theory prevented one-off keying errors (never heard what the error rate actually was).

  • Hatterson (unregistered) in reply to A Gould
    A Gould:
    DocBrown:
    TRWTF is.. Why non-sequential?

    Probably to reduce user-error (someone typing 04 instead of 05 and coding to the wrong activity).

    Our old system ran 3-3-13 (1,4,7,20,23,26,39...), which in theory prevented one-off keying errors (never heard what the error rate actually was).

    Still doesn't move the one key off keying error when using a numpad. Adding 3 will move the next one up a row more than half the time.

  • asdf (unregistered)
     public static class SequenceGenerator
    {
        static int index = -1;
        static string[] sequence = new string[] { "42", "08", "17", "86", "39", "12", "02", "98" };
        public static string GetNextSequence()
        {
            index++; if (index > 7) index = 0; return sequence[index];
        }
    
    }
    

    This is a trivial problem to meet the requirements, AS WRITTEN. I leave it up to the reader to expand it to the full 48 candidates.

  • justvisiting (unregistered) in reply to TGVish
    TGVish:
    The probability that two people in a group share the same birthday is 50% when there are more than 23 people, and that's with 365 numbers to chose from. So yes, you did miss something, like probability 101.

    Someone certainly missed probability 101. The chance of repeated birthdays if you pick 23 people at random is ~50%, but the chance of picking a repeated 24th birthday after you already have 23 people with guaranteed different birthdays is much lower (23/365). In fact, the calculation you did is identical to the GP's, he just did it for 25 instead of 47 since that's when they started seeing problems according to the OP.

  • sd (unregistered) in reply to ipeet
    ipeet:
    Apparently people don't understand The Birthday Problem. http://en.wikipedia.org/wiki/Birthday_problem

    You can't just use a random number blindly, or you will have collisions, which will cause interesting things to happen if the random number happens to be an identifying index. This is what makes hash tables interesting.

    Random numbers are a good way to go, but you need some way to check for collision. For a small dataset, you can just use a lookup table. For a large dataset, where the memory cost of the lookup table is prohibitive, you can use a sorted list, or a hashtable, or etc... to reduce the complexity of lookup. As the article implies, there are plenty of valid solutions. This just isn't one of them.

    I think the birthday problem is a result of the fact that people tend to get drunk and forget birth control the same times each year.

    I have a lot of relatives whose birthdays are around the end of September. Happy New Year!

  • Hatterson (unregistered)

    If my numbers are not wrong (that's very possible given that I haven't really paid attention).

    The probability that it will makes it through a given number of runs (assuming all numbers are truly random) is in this google doc.

    http://spreadsheets.google.com/ccc?key=0AmIbKrZ2YBMTdHV0aXpKTWJqTENvM2dKSF9DRDViSmc&hl=en

  • fjf (unregistered) in reply to OldCoder
    OldCoder:
    All it's saying is that, in any period (e.g. a college teaching period) up to 48 activities may take place selected from a list of 100.
    Uhm, no, it's not.
  • fjf (unregistered) in reply to noland
    noland:
    This would make a good Perl golf question:
    Here we go

    [code]$id=sprintf('%02d',(1..48)[int(rand(47))+1]);[code]

    [code]$id=sprintf('%02d',rand(98)+1);[code] Eagle!

    [code]$id='01';[code] Hole in one!

    (Since we're ignoring the requirements anyway.)

  • qwerty (unregistered) in reply to asdf

    I was thinking something along the same lines however if you wanted to make it seem more "random":

    static List<string> sequence = new List<string> { "01", "03", "05", // ... etc "95", "97", "99"};

    public static string GetNextSequence() { Random r = new Random(); int ix = r.Next(sequence.Count); string id = sequence[ix]; sequence.RemoveAt(ix); return id; }

    It might have to be modified to meet specific needs but it would give id's in a seemingly random order that can't possibly be sequential and are guaranteed to be unique up to 50 items (in case the people writing the specification did want a sequence that could not be guessed at and didn't want sequential numbers such as "01" then "02", etc).

    I still don't really understand the requirements though in the sense that I can't see how something like that could possibly be useful.

    I'm thinking of a context like Period A has Activiy A and Activity B. Period B has Activity A. With the specification as it is Activity A could have an ID of "02" in Period A and an ID of "97" in Period B. Is that useful? I don't know, maybe? I would think that if each Activity had it's own unique ID relative to other Activities you wouldn't need all this other mess. Maybe I am just over-thinking it though @_@

  • fjf (unregistered) in reply to Mason Wheeler
    Mason Wheeler:
      for i := 0 to max do
        FList.Exchange(i, Random(max + 1));
    
    For an application liks this that doesn't actually require randomness, this might be alright, but in general that's a very bad way, see here.
  • Dan (unregistered)

    Maybe whoever wrote the requirement was a ransom negotiator.

    Give me 48 activities in non-sequential numbers or your code gets it.

  • Joe (unregistered)

    This could potentially be from management being concerned about security and wanting it randomized. Still doesn't justify the poor implementation.

  • (cs) in reply to Mason Wheeler
    Mason Wheeler:
    Anon:
    the beholder:
    Jellineck:
    Medezark:
    You would run out of unique identifiers after a few periods.
    I've found that you can run out of unique identifiers after a number of missed periods.
    When my wife missed her periods we had to start thinking on an identifier. It didn't have to be unique, though.

    Indeed. Just ask George Foreman (and 5 of his 10 children who are also called George Foreman).

    Also, in various parts of South America, it's not unusual for a family to have more than one daughter whose first name is Maria. They'll often go by their middle names.

    Oh...so that's how you solve the problem of like Marias.

  • Paster (unregistered) in reply to Charleh
    Charleh:
    Anonymous:
    Steve Johnstone:
    I would love to know what those requirements are for. Any solution that involves generating a random number has a chance of being wrong because true randomness can and will generate sequential numbers.
    Bear in mind that the requirements said nothing about the IDs being random. It was the idiot coder who decided that was a good idea, it certainly never came from the requirements.

    Can you have a non-random set of numbers that's not a sequence?

    If you want to be pedantic, then if it's a set, it by definition isn't a sequence, because a set doesn't have any specific order.

    However, in programming "a sequence" and "a sequential run of numbers" are not necessarily same thing, so it's perfectly normal to have a "non-sequential sequence". The meaning of "non-sequential sequence" I leave as an exercise to the reader (if you can't answer, I suggest avoiding professional software development, mostly for the sake of your own sanity).

  • Alex (unregistered) in reply to Erasmus Darwin

    If I asked a client whether random numbers would be an acceptable "non-sequential" way of getting two-digit IDs or if he should clean up his specification, I would be fired on the spot for wasting someone's time over trivial nonsense. Obviously random is a perfectly acceptable implementation.

  • Sean O'Brien (unregistered)

    I read through this quickly, so perhaps I'm missing something, but it seems to me that you could just generate an array of 48 unique numbers and shuffle them. Once a number has been used, remove it from the array. Once all the numbers are used, start over.

    I've written a chunk of PHP that grabs the filenames of images from a specific folder, dumps the filenames into an array, shuffles the array, and then prints out the value of the first index when a webpage loads. Then it just removes that index from the array. The array is generated with a new browser session or once the array is empty.

Leave a comment on “Something Weird”

Log In or post as a guest

Replying to comment #:

« Return to Article