0

I'm working in Perl.

I start from a tab-delimited txt file with two columns.

cat1    val1
cat1    val2
cat2    val3 
cat3    val4
cat1    val5
cat4    val6

I want to push the unique categories from column 1 into an array & create empty variables that have the same name as these unique categories

so at the end I would have:

@unique_categories = ("cat1", "cat2", "cat3", "cat4");

$cat1 = '';
$cat2 = '';
$cat3 = '';
$cat4 = '';

This is what I've tried:

#! /usr/bin/perl
use strict;
use warnings;

open(my $file,'<',"file.txt") || die ("Could not open file $!"); #input file

my $categories = '';
my @categories_unique = '';

while(<$file>){
    chomp;
    my $line = $_;
    my @elements = split ("\t", $line);
    $categories = $elements[0]; #everything seems fine until here
    push(@categories_unique, $categories) unless grep{$_ eq $categories} @categories_unique; #with this line I want to store the unique values in an array
    #here I want to create the empty variables, but don't know how to
}
1
  • Why do you want to create those empty variables? Using those categories as keys to a hash sounds more reasonable; any reason to not do that? Commented Apr 11, 2019 at 14:03

2 Answers 2

4

Having variables with dynamically created names is dangerous, see Why it's stupid to `use a variable as a variable name' and A More Direct Explanation of the Problem.

In Perl, you can use a hash to both keep the unique values, and also instead of the variables of unknown names. It's also much faster then iterating the whole array every time.

#! /usr/bin/perl
use strict;
use warnings;

open my $fh, '<', 'file.txt' or "Could not open file $!";
my %categories;

while (my $line = <$fh>) {
    chomp $line;
    my @elements = split /\t/, $line;
    ++$categories{ $elements[0] };
}
my @categories = keys %categories;

Right now, the values of the %categories hash is simply the number of times that category is present. For example, $categories{cat1} is 3. If you decide you want the values for each category instead, it's simply a question of replacing

++$categories{ $elements[0] };

with

push @{ $categories{ $elements[0] } }, $elements[1];
Sign up to request clarification or add additional context in comments.

Comments

-1

Not a bad first attempt. here's what you need

#! /usr/bin/perl
use strict;
use warnings;

open(my $file,'<',"file.txt") || die ("Could not open file $!"); #input file

my %categories_unique = ();
my @categories_unique = ();

while(<$file>){
    chomp;
    my $line = $_;
    my @elements = split ("\t", $line);
    $categories = $elements[0]; #everything seems fine until here
    $categories_unique{$categories} = 1; # Use the fact that keys in a hash are unique
}

@categories_unique = keys %categories_unique;
{
    no strict 'refs'; # allows access to symbol table
    *{$_} = undef() foreach @categories_unique; create a symbol table entry 
}

2 Comments

Aside from the major problem of endorsing dynamically created variables, there are a number of small issues:
1) Assigning empty lists to empty arrays and empty hashes is useless. 2) Start with $_ and switching to $line later makes no sense. Stick to one or the other. 3) Unless it's ' ', the first argument to split is a regex pattern, so don't pretend it's not. 4) Don't declare variables far earlier than they are needed. The point of declaring variables is to limit their scope. 5) This is the first time I've ever seen undef() used instead of undef. It's just weird. 6) _unique doesn't really add anything to those var names.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.