mkHun
mkHun

Reputation: 5927

How to print a particular column from tabular data

I'm Trying to print columns from data by using index key value in the outer part of a foreach loop.

my @col;
foreach(<DATA>){
    @x = split(' ',$_);
@xz = ($x[0],$x[1],$x[2]) ;
    #print "$x[0]\n"; This is working but i'm not expect this.
push(@col,@xz);
} 
print "$col[0]\n";
__DATA__
7       2       3

3       2       8

6       7       2

I expect the output is

7 3 6 

How can i do it?

Upvotes: 1

Views: 126

Answers (5)

David W.
David W.

Reputation: 107040

Always use use strict; and use warnings;!!

You have a couple of issues:

push( @col, @xz );

In this case, you're losing your information in @xz array. After this loop, you end up with a single array that looks like this:

@col = ( 7, 2, 3, 3, 2, 8, 6, 7, 2);

So, when you print:

print "$col[0]\n";

You get that zeroth element: 7.

We can preserve the structure of the data by using a reference:

#! /usr/bin/env perl
#
    use strict;             # Lets you know when you misspell variable names
    use warnings;           # Warns of issues (using undefined variables

    use feature qw(say);
    use Data::Dumper;

    my @columns;
    for my $data ( <DATA> ) {
        my @data_list = split /\s+/, $data;
        push @columns, \@data_list;
}

say Dumper \@columns;

__DATA__
7       2       3
3       2       8
6       7       2

Here you see I've included Data::Dumper to print out the structure of @columns:

$VAR1 = [
          [
            '7',
            '2',
            '3'
          ],
          [
            '3',
            '2',
            '8'
          ],
          [
            '6',
            '7',
            '2'
          ]
      ];

As you can see, each entry in the @columns array is now another array. However, printing out $columns[0] array reference isn't going to print what you want. Instead, it's going to print the zeroth array reference: 7, 2, 3, and not the zeroth element of each array reference: 7, 3, 6.

To do that, we need a subroutine that will go through @columns and print out the the zeroth entry of each of the arrays. Here I'm creating a subroutine called fetch_index that will fetch the passed index of the passed array:

#! /usr/bin/env perl
#
    use strict;             # Lets you know when you misspell variable names
    use warnings;           # Warns of issues (using undefined variables

    use feature qw(say);
    use Data::Dumper;

    my @columns;
    for my $data ( <DATA> ) {
        my @data_list = split /\s*/, $data;
        push @columns, \@data_list;
}

say join ", ", fetch_index( 0, @columns );

sub fetch_index {
    my $entry = shift;     #Entry you want from all arrays
    my @array = @_;

    my @values;

    for my $array_ref ( @array ) {
        push @values, ${array_ref}->[$entry];
    }
    return @values;
}

__DATA__
7       2       3
3       2       8
6       7       2

The subroutine merely goes through each array reference I've stored in my array, and fetched the $entry value from that array reference. I push those into my @values array and return that.

Upvotes: 3

perl -a -F' ' -ne 'print "$F[0]\n";' data.txt

here you $F[0] is field you can change it accordingly you will get the expected output

Upvotes: 0

Ron Bergin
Ron Bergin

Reputation: 1068

my @col;
while (<DATA>) {
    push @col, (split ' ')[0];
    # push @col, /(\S+)/; # split alternative
}
print "@col\n";

__DATA__
7       2       3

3       2       8

6       7       2

output

7 3 6

Upvotes: 2

G. Cito
G. Cito

Reputation: 6378

Once you've absorbed the information about anonymous arrays and references in the other excellent posts here, you can start to have fun. e.g. you can often get a one liner approach to work:

perl -nE 'say [split]->[1] ' col_data.txt  

would loop (-n creates an implicit while(){} loop) through the data in col_data.txt, split the topic variable ($_) creating a series of anonymous arrays from each row and then print the second element, or "column" for example.

You can use the autosplit command line option (-a) to split each row into an array called @F (mnemonic: "F" for "Field"). In later versions of perl, the -a implies the implicit while loop (-n):

perl -anE 'say $F[1] ' col_data.txt

would be the equivalent of the previous command - printing the second column:

output:

2
2
7

There is a famous and short perl workalike for cut that is a more featureful variaton on this theme, and there is this Perl Monks thread.

Upvotes: 0

rchang
rchang

Reputation: 5236

You were pretty close I think. This is what I did (edited to reflect comments from @Borodin):

use strict;
use warnings;

sub getColumn {
  my ($data, $col) = @_;
  my @output = map $_->[$col], @{$data};
  return @output;
}

my @data;
while (<DATA>){
    push(@data, [split(' ',$_)]);
}
print join(' ', getColumn(\@data, 0), "\n");
print join(' ', getColumn(\@data, 1), "\n");
print join(' ', getColumn(\@data, 2), "\n");

__DATA__
7       2       3
3       2       8
6       7       2

That subroutine getColumn should let you retrieve any arbitrary column. When I ran it with your data I got this for output:

7 3 6
2 2 7
3 8 2

Upvotes: -1

Related Questions