array comparision

Discussion in 'Perl Misc' started by Marek, Aug 16, 2008.

  1. Marek

    Marek Guest

    Hello all!


    I have several lines where I need to know whether the numbers are the
    same or not.

    I made an example, and my questions are inserted as comments:

    Thank you for your help


    marek


    #! /usr/local/bin/perl

    use warnings;
    use strict;

    my $line1 = "Mon, 04.08.2008 61126.10 79071.30 3567 2648.00 2864.00";
    my $line2 =
    "Die, 05.08.2008 7:40-19:40 12:00 61198.70 79103.40 3574 2648.00
    2950.70 Name1";

    my @array1 = split( /\t\s*/, $line1 );
    my @array2 = split( /\t\s*/, $line2 );

    my @array3;
    for (@array1) { push @array3, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };
    # do I really need a different array, to "slice out" my numbers?
    # Is there not a more elegant (perlish) way to do this?
    my @array4;
    for (@array2) { push @array4, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };

    my $same = 1;
    $same = $same && @array3 == @array4;
    # this compares only the number of elements of these arrays.
    # how to iterate over each element and compare them?

    if ($same) {
    print "these numbers are the same!\n";
    print join( "\t", @array3 );
    print "\n";
    print join( "\t", @array4 );
    print "\n";
    }
    else {
    print "these numbers are not the same!\n\n";
    print join( "\t", @array3 );
    print "\n";
    print join( "\t", @array4 );
    print "\n";
    }
     
    Marek, Aug 16, 2008
    #1
    1. Advertising

  2. Marek

    Ben Morrow Guest

    Quoth Marek <>:
    >
    > Hello all!
    >
    >
    > I have several lines where I need to know whether the numbers are the
    > same or not.
    >
    > I made an example, and my questions are inserted as comments:
    >
    > Thank you for your help
    >
    >
    > marek
    >
    >
    > #! /usr/local/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $line1 = "Mon, 04.08.2008 61126.10 79071.30 3567 2648.00 2864.00";
    > my $line2 =
    > "Die, 05.08.2008 7:40-19:40 12:00 61198.70 79103.40 3574 2648.00
    > 2950.70 Name1";
    >
    > my @array1 = split( /\t\s*/, $line1 );
    > my @array2 = split( /\t\s*/, $line2 );
    >
    > my @array3;
    > for (@array1) { push @array3, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };
    > # do I really need a different array, to "slice out" my numbers?
    > # Is there not a more elegant (perlish) way to do this?


    Yes, you can use 'map', like this:

    my @array3 =
    map { /^\d+(?:\.\d+)?$/ ? $_ : () }
    split /\t\s*/,
    $line1;

    > my @array4;
    > for (@array2) { push @array4, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };
    >
    > my $same = 1;
    > $same = $same && @array3 == @array4;
    > # this compares only the number of elements of these arrays.
    > # how to iterate over each element and compare them?


    Well, the obvious way is

    my $same =
    @array3 == @array4 &&
    !grep { $array3[$_] == $array4[$_] } 0..$#array3;

    but it would be better to use a module like Data::Compare

    use Data::Compare;

    my $same = Compare \@array3, \@array4;

    Ben

    --
    Like all men in Babylon I have been a proconsul; like all, a slave ... During
    one lunar year, I have been declared invisible; I shrieked and was not heard,
    I stole my bread and was not decapitated.
    ~ ~ Jorge Luis Borges, 'The Babylon Lottery'
     
    Ben Morrow, Aug 16, 2008
    #2
    1. Advertising

  3. Marek

    h3xx Guest

    On Aug 16, 12:22 am, Marek <> wrote:
    > Hello all!
    >
    > I have several lines where I need to know whether the numbers are the
    > same or not.
    >
    > I made an example, and my questions are inserted as comments:
    >
    > Thank you for your help
    >
    > marek
    >
    > #! /usr/local/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $line1 = "Mon, 04.08.2008       61126.10        79071.30        3567    2648.00 2864.00";
    > my $line2 =
    > "Die, 05.08.2008 7:40-19:40        12:00   61198.70       79103.40        3574    2648.00
    > 2950.70 Name1";
    >
    > my @array1 = split( /\t\s*/, $line1 );
    > my @array2 = split( /\t\s*/, $line2 );


    /\s/ here will match any whitespace character. The \t is unnecessary.

    >
    > my @array3;
    > for (@array1) { push @array3, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };
    >    # do I really need a different array, to "slice out" my numbers?
    >    # Is there not a more elegant (perlish) way to do this?
    > my @array4;
    > for (@array2) { push @array4, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };
    >
    > my $same = 1;
    > $same = $same && @array3 == @array4;
    >   # this compares only the number of elements of these arrays.
    >   # how to iterate over each element and compare them?
    >
    > if ($same) {
    >     print "these numbers are the same!\n";
    >     print join( "\t", @array3 );
    >     print "\n";
    >     print join( "\t", @array4 );
    >     print "\n";}
    >
    > else {
    >     print "these numbers are not the same!\n\n";
    >     print join( "\t", @array3 );
    >     print "\n";
    >     print join( "\t", @array4 );
    >     print "\n";
    >
    > }
    >
    >


    Looks like you want to do it this way:

    # find the numbers in the split arrays
    my @nums1 = grep { /^\d+([:.]\d+)*$/ } @array1;
    my @nums2 = grep { /^\d+([:.]\d+)*$/ } @array2;

    # to be set upon first difference
    my $fail = 0;

    # check each member by the indexes
    map {
    $fail = 1 unless $nums1[$_] == $nums2[$_]
    } 0 .. $#nums1;


    if ($fail) {
        print "these numbers are not the same!\n\n",
        join ("\t", @array3),
    "\n",
    join ("\t", @array4),
    "\n";
    } else {
        print "these numbers are the same!\n",
        join ("\t", @array3),
    "\n",
    join ("\t", @array4),
    "\n";
    }
     
    h3xx, Aug 16, 2008
    #3
  4. Marek

    h3xx Guest

    On Aug 16, 3:45 am, Ben Morrow <> wrote:
    > Quoth Marek <>:
    >
    > but it would be better to use a module like Data::Compare
    >
    >     use Data::Compare;
    >
    >     my $same = Compare \@array3, \@array4;
    >
    > Ben


    Nice! I didn't even know of that one.
     
    h3xx, Aug 16, 2008
    #4
  5. h3xx <> wrote:
    >On Aug 16, 12:22 am, Marek <> wrote:


    >> my @array1 = split( /\t\s*/, $line1 );
    >> my @array2 = split( /\t\s*/, $line2 );

    >
    >/\s/ here will match any whitespace character. The \t is unnecessary.


    Depends on what the OP wants to match. /\t\s*/ and /\s*/ (and even /\s+/
    for that matter) match different sets of strings. A plain /\s*/ neither
    enforces a tab at the beginning nor at least one character.

    jue
     
    Jürgen Exner, Aug 16, 2008
    #5
  6. Marek <> wrote:

    >for (@array1) { push @array3, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };


    The match operator defaults to $_. No need to explicitely bind $_.

    > # do I really need a different array, to "slice out" my numbers?
    > # Is there not a more elegant (perlish) way to do this?


    It appears to me as if you may be looking for grep():
    @array3 = grep(/^\d+(?:\.\d+)?$/, @array1);

    >my $same = 1;
    >$same = $same && @array3 == @array4;
    > # this compares only the number of elements of these arrays.
    > # how to iterate over each element and compare them?


    I am not sure I understand. Do you want to know if _all_ numbers are
    equal (i.e. the arrays have the same content) or do you want to sort the
    numbers into two groups based on equal/non equal?

    If the former then just loop over them, either with a C-style loop or
    with a foreach loop (assuming they are equal length):

    for ($i = 0; $i < @array3, $i++) {
    $same = $same && $array3[$i] == $array4[$i];
    }

    or

    for (@array3){
    $same = $same && $_ == shift @array4;
    }

    Or you can use map() in scalar context:
    $diff= map( $array3[$_]==$array4[$_] ? ():(1), (0..$#array3));
    print "All numbers are the same\n" unless $diff;

    You can also use map() to get a list of indices for which the numbers
    are equal or different although IMO grep() is the better candidate for
    that:
    grep($array3[$_]==$array4[$_], 0..$#array3);

    If you rather want the values instead of the indices then just return
    those from map():
    @same = map( $array3[$_]==$array4[$_]? ($array3[$_]) : (),
    0..$#array3);

    jue
     
    Jürgen Exner, Aug 16, 2008
    #6
  7. Marek <> wrote:

    *SKIP*
    > for (@array1) { push @array3, $_ if $_ =~ /^\d+(?:\.\d+)?$/ };


    Be prepared to have problems with that naive parsing. I don't say that
    that will fail for sure, but your data seems to be quite irregular.
    There can be Easter Eggs.

    Personally, I would match the whole line against complex RE with grabs
    and then C<push @array1, [ $1, $2, $3 ]>. Though that's my personal
    disease.

    *SKIP*
    > $same = $same && @array3 == @array4;


    There's something strange. The left part of C<&&> isn't comparision.
    It's assignment (you know).

    > # this compares only the number of elements of these arrays.
    > # how to iterate over each element and compare them?


    L<Array::Compare>?

    *CUT*

    --
    Torvalds' goal for Linux is very simple: World Domination
     
    Eric Pozharski, Aug 16, 2008
    #7
  8. Marek

    Ben Morrow Guest

    Quoth h3xx <>:
    >
    > # check each member by the indexes
    > map {
    > $fail = 1 unless $nums1[$_] == $nums2[$_]
    > } 0 .. $#nums1;


    Why are you using map in void context? I know it works, but it's rather
    bad style.

    for (0..$#nums1) {
    $fail = 1 unless $nums1[$_] == $nums2[$_];
    }

    Better would be to exit the loop early as soon as you know it will fail,
    viz.

    for (0..$#nums1) {
    unless ($nums1[$_] == $nums2[$_]) {
    $fail = 1;
    last;
    }
    }

    Ben

    --
    'Deserve [death]? I daresay he did. Many live that deserve death. And some die
    that deserve life. Can you give it to them? Then do not be too eager to deal
    out death in judgement. For even the very wise cannot see all ends.'
     
    Ben Morrow, Aug 16, 2008
    #8
  9. Marek

    Marek Guest

    Thank you all for your great answers! I learned a lot!


    greetigs from Munich


    marek
     
    Marek, Aug 17, 2008
    #9
  10. Marek

    Dr.Ruud Guest

    Nonni Nil schreef:
    > Marek:


    >> my @array1 = split( /\t\s*/, $line1 );

    >
    > did you mean my @array1 = split( /[\t\s]*/, $line1 ); ?



    Not very likely, because "[\t\s]" is equivalent to just "\s". You were
    probably looking for "\s+", but you were losing that the TAB should be
    at the start and that the full regex should match 1-or-more, not
    0-or-more.

    More likely, OP meant that the field separator is TAB, and the fields
    have optional SPC's at the start.
    So OP was probably looking for /\t */.

    In two steps it is clearer:

    my @values = split /\t/, $line; # FS is TAB
    s/^ +// for @values; # ltrim

    --
    Affijn, Ruud

    "Gewoon is een tijger."
     
    Dr.Ruud, Aug 17, 2008
    #10
  11. Marek

    Marek Guest

    Yes Affijn, yes, my field separator is <TAB>. And just in case a field
    is starting with a <space>, I added a \s*; but this was superfluous.
    There are no spaces at the beginning. Thank you again for all your
    very helpful answers :)


    ps: my posting from 3rd August is still not answered :))) Just in
    case you have some ideas again: "Debugger: Pipe print output into
    shell" :)))
     
    Marek, Aug 18, 2008
    #11
  12. Marek

    Guest

    On Aug 16, 7:22 am, Marek <> wrote:
    > Hello all!
    >
    > I have several lines where I need to know whether the numbers are the
    > same or not.
    >
    > I made an example, and my questions are inserted as comments:
    >
    > Thank you for your help
    >
    > marek
    >
    > #! /usr/local/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $line1 = "Mon, 04.08.2008 61126.10 79071.30 3567 2648.00 2864.00";
    > my $line2 =
    > "Die, 05.08.2008 7:40-19:40 12:00 61198.70 79103.40 3574 2648.00
    > 2950.70 Name1";
    >


    Just for the fun of Perl

    $line1 =~ s/.*?\t\s*(\d+(\.\d+)?)/(.+?)$1/g;
    print $line2 =~ /^$line1$/ ? "same\n" : "not same\n";

    This however, requires a constant decimal notation and wouldn't help
    you much if you always need your numbers for a closer inspection.
    Still it might be the 'perlish' way that helps find the occasional
    discrepancy.


    Regards, Steffen
     
    , Aug 18, 2008
    #12
  13. Marek

    Willem Guest

    Ben Morrow wrote:
    )
    ) Quoth h3xx <>:
    )>
    )> # check each member by the indexes
    )> map {
    )> $fail = 1 unless $nums1[$_] == $nums2[$_]
    )> } 0 .. $#nums1;
    )
    ) Why are you using map in void context? I know it works, but it's rather
    ) bad style.
    )
    ) for (0..$#nums1) {
    ) $fail = 1 unless $nums1[$_] == $nums2[$_];
    ) }

    True.

    ) Better would be to exit the loop early as soon as you know it will fail,
    ) viz.
    )
    ) for (0..$#nums1) {
    ) unless ($nums1[$_] == $nums2[$_]) {
    ) $fail = 1;
    ) last;
    ) }
    ) }

    If you look further you will see he then prints all differing numbers.


    SaSW, Willem
    --
    Disclaimer: I am in no way responsible for any of the statements
    made in the above text. For all I know I might be
    drugged or something..
    No I'm not paranoid. You all think I'm paranoid, don't you !
    #EOT
     
    Willem, Aug 18, 2008
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. john

    Comparision

    john, Mar 17, 2005, in forum: VHDL
    Replies:
    2
    Views:
    496
    Mike Treseler
    Mar 17, 2005
  2. Viktor Popov

    stored procedure result comparision

    Viktor Popov, Jul 20, 2004, in forum: ASP .Net
    Replies:
    9
    Views:
    567
    Viktor Popov
    Jul 20, 2004
  3. Stephen

    String Comparision

    Stephen, Sep 30, 2004, in forum: ASP .Net
    Replies:
    4
    Views:
    480
    Kevin Spencer
    Oct 1, 2004
  4. zzyzx

    Date comparision

    zzyzx, Jul 23, 2004, in forum: Java
    Replies:
    10
    Views:
    5,362
    Roedy Green
    Jul 24, 2004
  5. Daniel

    String comparision efficency

    Daniel, Feb 14, 2005, in forum: Java
    Replies:
    14
    Views:
    1,829
    Daniel
    Feb 16, 2005
Loading...

Share This Page