1

I need to set up a recursive function in C# to set the sequence number of a list of items. More specifically a bom. For each bom level, I need to start the sequence at 10, and increment of 10. How do I keep track of what level i'm at, and what counter to increment. This is driving me nuts.

Short example of data below, the real boms have thousands of lines and up to 12-15 levels.

Order Level Sequence
1 1 10
2 2 10
3 3 10
4 3 20
5 2 20
6 3 10
7 4 10
8 3 20
9 4 10
10 4 20
11 2 30
12 3 10
13 1 20
14 1 30

I indented the levels, to make the structure a bit more clear. And pasted the results of your answer to this. As you can see, the new levels are not sequenced properly.

enter image description here

  • 3
    I think you need to provide a better sample data and expected output. It doesn't likely that someone would understand what you are asking as is. A BOM table normally looks like id, ParentId. I don't see something like that in your sample. – Cetin Basoz Oct 17 '21 at 13:36
  • fun little problem even with simplified data though :) – T. Nielsen Oct 17 '21 at 14:27

1 Answers1

0

I think i this case we can use the new language feature local function, and see if a recursive function is really necessary, as they are generally some of the hardest code to debug and maintain, only to be used sparingly, if at all this year, for any given year :)

    [Fact]
    public void SequencingRecursiveTest()
    {
        //  BOM like byte order mark in utf 8 text encoding? odd problem :D
        // Anyway we have a long list of values and want to emit the value with a sequence number, starting from 10 with increment 10
        // Like in most cases when contemplating recursion, first off  what about not using recursion to keep code maintainable and clean,
        // As it turns out, we can:

        //However super sneakily we have to reset all 'bom' sequence counts below the highest when an element in the sequence breaks the chain of same or greater

        var keyValues = new Dictionary<int, int>();
        var firstValue = 10;
        var increment = 10;
        int lastBom = 0;
        int greatesBom = 0;

        KeyValuePair<int, int> GetValueWithSequenceResetIfLowerThanLast(int bom)
        {
            bool reset = bom < lastBom;
            greatesBom = bom > greatesBom ? bom : greatesBom;

            if (reset)
            {
                foreach (int keyBom in keyValues.Keys)
                {
                    if (keyBom < greatesBom)
                        keyValues[keyBom] = firstValue;
                }
            }
            else if (keyValues.ContainsKey(bom))
            {
                keyValues[bom] = keyValues[bom] + increment;
            }
            else
            {
                keyValues.Add(bom, firstValue);
            }
            lastBom = bom;
            return new KeyValuePair<int, int>(bom, keyValues[bom]);
        }

        var valueList = new List<int> { 1, 2, 3, 3, 2, 3, 4, 3, 4, 4, 2, 3, 1, 1 };
        var valueSequenceList = valueList.Aggregate(
            new List<KeyValuePair<int, int>>(),
            (source, item) =>
            {
                source.Add(GetValueWithSequenceResetIfLowerThanLast(item));
                return source;
            }
        );

        foreach (var element in valueSequenceList)
            System.Diagnostics.Debug.WriteLine($"{element.Key}: {element.Value}");

    }
T. Nielsen
  • 835
  • 5
  • 18
  • I really like your approach, However it seems to not work pass level 2, I am trying to post the result and mode supporting data in this comment, but it's not cooperating. See original question for added info – André Cooke Oct 17 '21 at 15:12
  • @AndréCooke do you mean it is not sorted? by the looks of your screenshot also the sequence is correctly sequential from beginning per number each with a jump of 10 for each new time it happens. Did i perhaps not understand what you're trying to achieve? if sorting you may want to: valueSequenceList.OrderBy(a => a.Key).ThenBy(b => b.Value); – T. Nielsen Oct 17 '21 at 16:11
  • I omitted the sort key for simplicity, but the order is from top to bottom. I added it to the original post. The issue is how to reset the counter when hitting a new lower branch in the BOM list as in the item at line order 6, new lower branch starts at 10 again, when we go back up one level we continue the previous sequence. Not sure if my explanation is clearer. – André Cooke Oct 17 '21 at 17:15
  • @AndréCooke I think so, a bit if I managed to get the intend this time, will post update – T. Nielsen Oct 17 '21 at 17:48
  • @AndréCooke so if you want to reset all of lower value than the max when the chain is broken or just all lower than the breaking offender, you may or may not need the greatestBom value else can base on the lastBom to reset – T. Nielsen Oct 17 '21 at 18:29
  • Did you get it running ?, I get an exception {"Collection was modified; enumeration operation may not execute."} – André Cooke Oct 17 '21 at 18:39
  • Yes the test executes with the series provided to give the following result sequence: 1: 10, 2: 10, 3: 10, 3: 20, 2: 10, 3: 30, 4: 10, 3: 10, 4: 20, 4: 30, 2: 10, 3: 20, 1: 10, 1: 20 I do not see any adds in enumerations, did you run the same code? – T. Nielsen Oct 17 '21 at 18:45
  • yes was running same code, minus the [Fact], as it was not resolving, perhaps I am missing a reference. I will take a break from this problem for a few hours, I cannot seem to wrap my head around the solution. – André Cooke Oct 17 '21 at 19:06
  • the fact is just the xUnit way of say to run it as a test, shouldn't change execution as such – T. Nielsen Oct 18 '21 at 07:56