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

Hello PerlMonks I have problem with using Text::CSV, just don`t understand routines. I have 3 tables @list, @val1, @val2, I need to create CSV file with content like this pattern:

filename(which is always the same);$list[0];$val1[0];$val2[0]; filename;$list[n];$val1[n];$val2[n];

this is part of a bigger script, this is just concerning cut:

my $csv = Text::CSV->new({sep_char => ';'}); open (CSV, ">", "base.csv") or die $!; if ($csv->combine(@list)){ print CSV $csv->string "\n"; } else { print "combine () failed on argument: ", $csv->error_input, "\n"; }

I wanted to add to such existing file next arrays, but above itself is not working properly, printing all array to one field.How to refer to specific columnd and row in creating csv.Don`t understand documentation for this module. Thanks in advance.

Replies are listed 'Best First'.
Re: Creating CSV file
by roboticus (Chancellor) on Jul 31, 2010 at 15:13 UTC

    reez:

    Your problem description isn't very clear, but I don't see anything in the code that should be a problem. If you can provide a bit more context to your problem, and clarify what your problem is, we can give a bit better guidance.

    If you can boil it down to a small program with the actual and intended output, it would be helpful. Something like:


    Hello, I'm having trouble with the Text::CSV module. My problem is that it's formatting the output different than I expect. A sample program to show the problem is:

    my @list = qq(1 2 3 4); my $csv = Text::CSV->new({sep_char => ';'}); open (CSV, ">", "base.csv") or die $!; if ($csv->combine(@list)){ print CSV $csv->string "\n"; } else { print "combine () failed on argument: ", $csv->error_input, "\n"; }

    The output I wanted to see is:

    1 2 3 4

    but the output I received is:

    1;2;3;4

    ...roboticus

      OK I`ll try: During processing in previous part of a program I received following three arrays:

      @ports=qw(portname portID port802); @val1= qw(ON ON OFF); @val2=qw(EX EX NEX);

      Output i received:

      portname;portID;port802;

      What i need is to print in CSV something like this:

      ports;portname;ON;EX; ports;portID;ON;EX; ports;port802;OFF;NEX;

      Hope this will clarify a little bit, just don`t know how to get this using Text::CSV module.

        Here data structure is the key. It looks like you are using three arrays in parallel to manage data records. Instead you should be using an array of records - each record being either a hash or an array as you think most appropriate. Consider:

        #!/usr/bin/perl use strict; use warnings; use Text::CSV; my @ports = qw(portname portID port802); my @val1 = qw(ON ON OFF); my @val2 = qw(EX EX NEX); my @records; while (@ports) { push @records, [shift @ports, shift @val1, shift @val2]; } my $csv = Text::CSV->new ({sep_char => ';'}); for my $record (@records) { if ($csv->combine (@$record)) { print $csv->string, "\n"; } else { print "combine () failed on argument: ", $csv->error_input, "\ +n"; } }

        Prints:

        portname;ON;EX portID;ON;EX port802;OFF;NEX

        Note that much of the rest of your program would likely benefit from using record oriented storage as illustrated rather than scattering related data across disparate arrays as indicated in your sample.

        True laziness is hard work
        I'm not sure that you need Text::CSV to get the output you want. The following subroutine will do what you describe:
        sub combine_rows { my ( $label, @arrays ) = @_; my @joined; for my $i ( 0 .. $#{$arrays[0]} ) { # assumes that all arrays are + the same size push @joined, join( ';', $label, map { $arrays[$_][$i] } 0 .. +$#arrays ); } return \@joined; }
        Here's how you would use the subroutine:
        @ports = qw( portname portID port802 ); @val1 = qw( ON ON OFF ); @val2 = qw( EX EX NEX ); my $joined = combine_rows( "ports", \@ports, \@val1, \@val2 ); print "$_\n" for ( @$joined );
        Now, it would be a little more complicated if your input array values can contain the semi-colon character as data. In that case, you need to escape or quote the field values in the subroutine. (That's the sort of thing Text::CSV would do for you if you used it properly, but it's not that complicated to do on your own.)

        The reason I use "map" in the subroutine is to allow it to join any number of parallel arrays (not just exactly 3, as in your "@ports, @val1, @val2" example). If you can't figure out what "map" is doing there, it's just a nested loop to get the $i'th value of each input array.

Re: Creating CSV file
by Anonymous Monk on Jul 31, 2010 at 15:01 UTC
    I wanted to add to such existing file next arrays, but above itself is not working properly, printing all array to one field.

    What is @list? Your problem is you have @list = "1,2,3";

    How (Not) To Ask A Question