http://www.perlmonks.org?node_id=982974


in reply to Re: Nested Data Structures, OOP
in thread Nested Data Structures, OOP

Thanks, now it is working

How about if I push "C++" and "Java" into the complex data by using

$student1->add_courses(["C++", "Java"]);?

I couldn't find in Internet info about pushing the array into a compl. data like

$self->{"Course(s)"}=[<STDIN>]

First, at the user interface I enter some data (like: Enter the courses: C, PHP |CTRL+D|) and then program must push additionals by $student1->add_courses(["C++", "Java"]). How can I use properly my push() func. to this data structure? This func. that I wrote isn't working:

sub add_courses { $self = shift; $courses = shift; push(@{$self{"Course(s)"}->[], $courses); }

Replies are listed 'Best First'.
Re^3: Nested Data Structures, OOP
by kcott (Archbishop) on Jul 21, 2012 at 13:28 UTC

    Firstly, "isn't working" is a totally inadequate error report: you need to post the error messages you are getting. If you're not getting any error messages, add use strict; and use warnings; near the start of your code. If you don't understand the messages, also add use diagnostics; for more verbose messages.

    Here's the basic syntax for pushing onto a simple and a complex array:

    # simple array push @simple_array, $array_element; my $simple_arrayref = \@simple_array; push @{ $simple_arrayref }, $array_element; # complex array push @{ $complex_arrayref }, $array_element;

    You'll note the absence of any ->[] in the above code.

    You have another problem in your push line above. Compare how you've written $self{"Course(s)"} here with how you've written it everywhere else.

    I hope that's enough for you to resolve the problem yourself. If not, post your error messages and describe what parts you're having difficulty with.

    Finally, there's all sorts of problems with your example push:

    $self->{"Course(s)"}=[<STDIN>]
    • It's an assignment, not a push.
    • You'd probably need [scalar <STDIN>] instead of [<STDIN>]
    • Your data will contain all the newlines that the user entered.

    Something like the following skeleton code would be better:

    while (<>) { chomp; push @array, $_; }

    -- Ken

      Yes, I made some simple mistakes, the reason was that I was confused on complex data structures. Now, I changed:

      print "Enter the student's course(s) "; $self->{"Course(s)"}=[<STDIN>]

      to

      print "Enter the student's course(s) delimiting them with a comma (,) "; chomp(my $cour = <STDIN>); $cour =~ s/\s+//g; my @cour = split(",", $cour); chomp($self->{"Course(s)"}->{"cour"}=[@cour]);
      -----------------------------------

      I renewed the push() method:

      sub add_courses { my $self = shift; my $courses = shift; # $courses = ["C++", "Java"]; my $num = @{$courses}; for ($i=0; $i<$num; $i++) { push @{$self->{'Course(s)'}->{'cour'}}, $courses->[$i]; }

      But, I'm having trouble with a deleting the element of an array, ofcourse :), here I'm attaching the output (error in the last line, if you see there are two commas), it seems that element is not being deleted, instead it's undefined. How to delete the element? I tried look into perldoc but I couldn't find another functions except 'delete' and 'undef'. Here in perldoc about 'delete' : WARNING: Calling delete on array values is deprecated and likely to be removed in a future version of Perl.

      Output of program:

      Here are the statistics for the Sino. Address: kk ID: kk Major: jj Start_Date: kk Tuition: kk Course(s): Chem, Bio, Maths, C++, Java After dropping: Chem, Bio, Maths, , Java

      Code of program and module:

      package Student3; sub new { my $class = shift; my $ref = {}; # Anonymous hash bless($ref, $class); return $ref; } sub set_student { my $self = shift; print "Enter the student's name "; chomp($self->{"Name"}=<STDIN>); print "Enter the student's major "; chomp($self->{"Major"}=<STDIN>); print "Enter the student's course(s) delimiting them with a comma (,) "; chomp(my $cour = <STDIN>); $cour =~ s/\s+//g; my @cour = split(",", $cour); chomp($self->{"Course(s)"}->{"cour"}=[@cour]); <...continues here...> } sub show_student { my $self = shift; print "Here are the statistics for the ", $self->{"Name"}, ".\n"; foreach $key (sort(keys %$self)) { if ($self->{$key} ne $self->{"Course(s)"}) { printf "%s: %s\n", $key, $self->{$key} unless $self->{$key} eq $self->{"Name"}; } } print "Course(s): ", join (", ", @{$self->{'Course(s)'}->{'cour'}}), "\n"; } sub add_courses { my $self = shift; my $courses = shift; my $num = @{$courses}; for ($i=0; $i<$num; $i++) { push @{$self->{'Course(s)'}->{'cour'}}, $courses->[$i]; } } sub drop_courses { my $self=shift; my $del_cour = shift; # $del_cour = ["Java"]; my $num = @{$del_cour}; if ($num == 1) { foreach $k (@{$self->{'Course(s)'}->{'cour'}}) { if ($k eq $del_cour->[0]) { $k=""; } } } print "After dropping: ", join (", ", @{$self->{'Course(s)'}->{'cour'}}), "\n"; } 1;

      The code of a program

      #!/usr/bin/perl -w use Student3; use warnings; use strict; my $student1 = Student3->new; $student1->set_student; $student1->show_student; $student1->add_courses(["C++", "Java"]); $student1->show_student; $student1->drop_courses(["C++"]);

        It's good to see you're paying attention to deprecation warnings.

        You can use the splice function to remove elements from an array. Here's an example:

        $ perl -Mstrict -Mwarnings -E ' my @x = qw{a b c}; say "@x"; splice @x, 1, 1; say "@x"; ' a b c a c

        If you know the value you want to delete but not the array index of that value, grep may be a better option:

        $ perl -Mstrict -Mwarnings -E ' my @x = qw{a b c}; say "@x"; @x = grep { $_ ne q{b} } @x; say "@x"; ' a b c a c

        Also, an empty list will not add elements to the array, e.g.

        $ perl -Mstrict -Mwarnings -E ' my @x = ( qw{a}, (), qw{c} ); say "@x"; ' a c

        You might use this feature in, for instance, a map statement. This example shows discarding certain values and modifying the remainder:

        $ perl -Mstrict -Mwarnings -E ' my @x = qw{a b c}; say "@x"; @x = map { $_ ne q{b} ? uc : () } @x; say "@x"; ' a b c A C

        You may also find the following modules useful:

        • List::Util - A selection of general-utility list subroutines.
          This is a builtin module; you should have it already.
        • List::MoreUtils - Provide the stuff missing in List::Util.
          This is a CPAN module; you may need to install it.

        -- Ken

      Hi Ken,

      The grep function helped me to delete the elements of an array. In my book (Perl by Example 4th edit.) there is no format of grep function, which you show me:

      @x = grep { $_ ne q{b} } @x;

      In the book, there is only one format: grep(EXPR,LIST). I used your format and it is working :-). Both calls: with single or multiple arguments are working:

      $student1->drop_courses(["C++"]); $student1->drop_courses(["C++", "Bio"]);

      Here is the final script of a sub:

      sub drop_courses { # drop_courses(["",]); my $self=shift; my $del_cour = shift; # $del_cour = ["Java"]; my $num = @{$del_cour}; if ($num == 1) { @{$self->{'Course(s)'}->{'cour'}} = grep { $_ ne $del_cour->[0] } @{$self->{'Course(s)'}->{'cour'}}; print "After dropping: ", join (", ", @{$self->{'Course(s)'}->{'cour'}}), "\n"; } elsif ($num > 1) { for ($i=0; $i<$num; $i++) { @{$self->{'Course(s)'}->{'cour'}} = grep { $_ ne $del_cour->[$i] } @{$self->{'Course(s)'}->{'cour'}}; } } print "After dropping: ", join (", ", @{$self->{'Course(s)'}->{'cour'}}), "\n"; }
      Thank you, Ken!