Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Comparing a Multilevel Bill of Materials

I have two BOMs (Bill of Material) for which I want to compare. The BOM consists of BOM Level, Part Number, Description, ECO#, Revision#. The BOMs are on the order of 17K-19K parts, different sub assemblies can have the same parts, so I have to treat each sub-assembly as a unique collection.

Here's what I want to collect:

  1. Any Change in ECO# or Revision# - This should not be too difficult. Pull all the unique PN into two hases and compare the hashes.
  2. Change in the parts that make up a sub assembly. Additions, subtractions ... This appears to be a little more difficult. These BOMs can be up to 15 levels deep. Each level would need to be checked and compared. I would assume this would require a loop within a loop.
  3. Once all the changes are found I need to go back and capture the highest level PN an ECO affects. i.e. if sub-assembly A is made up of xyz and a ECO change affected everything in the assembly I want to report back A, if the change only affected x and it's sub parts then I want x reported back but not A. (This is required to determine the extent the ECO effected the full assembly.
I hope this is a little changing to someone. I am really looking for guidance and different approaches to this problem so I can attack it without having to use a hammer.

Thanks!

Edit kudra, 2002-06-06 Replaced pre tags with some other markup

  • Comment on Comparing a Multilevel Bill of Materials

Replies are listed 'Best First'.
Re: Comparing a Multilevel Bill of Materials
by Aristotle (Chancellor) on Jun 06, 2002 at 21:59 UTC
    I checked this node soon after it was posted. Still no reply? Seems I was not the only one who is not entirely sure about your data format. Also, it appears you have a fairly good idea of what your script would have to do. Where did you run into a problem trying to implement it?

    Makeshifts last the longest.

      Sorry if I was not clear. It's perfectly clear in my head, why can't you see it!

      My BOMs looks like this.

      LEVEL,PartNumber,ECO#,Revision#
      
      Or looking at it in indent format
      1,PN1234,ECO9800,REV1
          2,PN12367,ECO9480,REV6
          2,PN54325,ECO9379,Rev0
              3,PN7888,ECO8790,Rev9
              ....
          2,PN8903,ECO909,Rev0
      1,PN5464,ECO9803,REV3
      ....
      
      So for example PN7888 is part of the assembly PN54325 which is one of three part/assemblies in PN1234. PN7888 has no relationship to PN12367 except that if you go far enough up the assemblies you have a common parent.

      Here are the problems.

      1. Compare revisions and ECOs for parts between BOMs. I can conceptually see how to do that. This is the one I can't get a good grasp on how to best program.
      2. Keep track of the parts that make up an assembly and identify additions, subtractions and replacements.
      The problem here is how do I do this efficiently. For example: if I am moving down the assembly and I reach PN1234, I would want to check all the 2 level parts under the assembly, on one pass, then go back and check all the level 3 parts under PN54325. And so on. This goes on and could reach 15-20K parts in 15 levels.

      What should I do load two sets of 20,000 entries into two hashes? I have read that it is more efficient to use a while loop and read the lines, one at a time. But once I have read all Level 2 in one assembly how do I go back for additional passes to pull the deeper assemblies.

      Edit kudra, 2002-06-08 Removed pre tags, added other markup

        BoM always seem difficult!

        A brute force approach is to stringify each part at each level and diff corresponding parts. As usual with brute force methods this could take more memory than you have.

        You seem to talking about a flat structure. My second thought is to build the nested structure for both your BoM then walk the trees. I see it as a hash with part# as key and an array of (references to) sub-parts as the value. So, for each part#, check whether it exists, if not add it (initially with an empty value). Add (a ref to) the new part to the parent.

        Does this make sense?