<?xml version="1.0" encoding="windows-1252"?>
<node id="570409" title="Build tree data structure from DB (flat) data; function golf" created="2006-08-30 11:32:26" updated="2006-08-30 07:32:26">
<type id="115">
perlquestion</type>
<author id="25626">
gryphon</author>
<data>
<field name="doctext">
&lt;p&gt;Greetings fellow monks,&lt;p&gt;

&lt;p&gt;After looking over a recent project, I noticed I had written similar code in several sections that effectively did the same thing: Grab data from a database (single query) and build a tree structure from that data. Each time, I was building a structure according to similar rules, so I decided to make a common function.&lt;/p&gt;

&lt;p&gt;What I've come up with works, but it has some repeated code. But what concerns me the most is that it's more or less a foreach loop that pushes to an array... which makes me want to rewrite it as a map. Anyway, I've been looking at  this for a while and am stuck. I'd like some pointers as to how I could improve the function.&lt;/p&gt;

&lt;code&gt;
sub tree_data {
  my ( $old_data, $key_name, $next_group, @remaining_keys ) = @_;
  my ( @new_data, $last_key, $build_box );

  foreach ( @{ $old_data } ) {
    if ( $last_key and ( $last_key ne $_-&gt;{ $key_name } ) ) {
      push @new_data, {
        $key_name   =&gt; $last_key,
        $next_group =&gt; ( @remaining_keys )
          ? tree_data( $build_box, @remaining_keys )
          : $build_box,
      };
      undef $build_box;
    }
    $last_key = delete $_-&gt;{ $key_name };
    push @{ $build_box }, $_;
  }
  push @new_data, {
    $key_name   =&gt; $last_key,
    $next_group =&gt; ( @remaining_keys )
      ? tree_data( $build_box, @remaining_keys )
      : $build_box,
  };

  return \@new_data;
}
&lt;/code&gt;

&lt;readmore&gt;

&lt;p&gt;What I'm trying to accomplish here is take data from a database call and build a tree from it based on key names. Here's some sample input:&lt;/p&gt;

&lt;code&gt;
my $input = [
  {
    'team'       =&gt; 'A-Team',

    'employee'   =&gt; 'Face',
    'work_day'   =&gt; '2006-08-28',
    'other_data' =&gt; '123456789',
  },
  {
    'team'       =&gt; 'A-Team',
    'employee'   =&gt; 'Murdock',
    'work_day'   =&gt; '2006-08-28',
    'other_data' =&gt; '123456789',
  },
  {
    'team'       =&gt; 'Military',
    'employee'   =&gt; 'Decker',
    'work_day'   =&gt; '2006-08-28',
    'other_data' =&gt; '123456789',
  },
];
&lt;/code&gt;

&lt;p&gt;Here's some sample output:&lt;/p&gt;

&lt;code&gt;
my $output = [
  {
    'team'      =&gt; 'A-Team',
    'employees' =&gt; [
      {
          'employee'   =&gt; 'Face',
          'work_day'   =&gt; '2006-08-28',
          'other_data' =&gt; '123456789',
      },
      {
          'employee'   =&gt; 'Murdock',
          'work_day'   =&gt; '2006-08-28',
          'other_data' =&gt; '123456789',
      },
    ],
  },
  {
    'team'      =&gt; 'Military',
    'employees' =&gt; [
      {
          'employee'   =&gt; 'Decker',
          'work_day'   =&gt; '2006-08-28',
          'other_data' =&gt; '123456789',
      },
    ],
  },
];
&lt;/code&gt;

&lt;p&gt;To call the function, I just pass in the data and the key name and sub-group name pairs I want, like this:&lt;/p&gt;

&lt;code&gt;
# ...to generate the output example from above...
my $output = tree_data( $input, 'team', 'employees' );

# ...to go a little deeper...
my $output = tree_data(
  $input, 'team', 'employees', 'employee', 'work_days'
);
&lt;/code&gt;

&lt;p&gt;Going forward, I'm probably going to want to add the ability to pull multiple keys into a particular level, not just a single key; but that's really out of scope for what I'm trying to accomplish right now.&lt;/p&gt;

&lt;/readmore&gt;

&lt;p&gt;What sort of things should I do to make this function better? Thanks in advance for your suggestions.&lt;/p&gt;

&lt;div class="pmsig"&gt;&lt;div class="pmsig-25626"&gt;
&lt;p&gt;[gryphon]&lt;br/&gt;
&lt;small&gt;Whitepages.com Development Manager (WDDC)&lt;/small&gt;&lt;br/&gt;
&lt;i&gt;code('Perl') || die;&lt;/i&gt;&lt;/p&gt;

&lt;/div&gt;&lt;/div&gt;</field>
</data>
</node>
