Putting 3 scalars at a time into an array

R

Rich Grise

Admittedly, I don't know the terminology well - suffice it to say,
I'm going through a file of the format:

Item1:<discard>Value1<discardthis>
<discard>
<discardItem2<discard>Value2<discard>
<discard>
<discard>Value3<discard>Item3<discard>
Item1:<discard>Value4<discardthis>
<discard>
<discardItem2<discard>Value5<discard>
<discard>
<discard>Value6<discard>Item3<discard>

which are kind of name-value pairs where "ItemX" is a name
and item "ValueX" is a value.

So, I've got it going through the file, picking lines
and building a little array: ($item1value,$item2value,$item3value),
which it printfs.

Now, I can rearrange the printf to put them in any order in
the output, so I could run stdout thru sort and sort by
any field, but then I'd have to rearrange that output
again.

So, obviously, I need to store these 3 items in an array,
like @ITEMS[$count] = ($a,$b,$c); and then increment $count,
is that right? Or would it make more sense to make a hash,
like %ITEMS{"$a"} = ($b,$c); , since in a way, $a is a name
that values $b and $c are associated with. Also, in my
reading, ISTR something about adding items to an array by
just adding them, and let perl take care of indexing, or
was that just hashes? Anyway, I'm reluctant to make a hash,
because can you then sort it on one of the item values? i.e.
sort "%ITEMS{"$a"} = ($b,$c)" on $b?

I guess the simple straightforward, non-arcane, way is:
$count = 0;
while (<>) {
# [get the 3 variables]
@items[$count++] = ($a, $b, $c);
}

But ISTVR something about #items, but don't know where to
look for it, if anyone has any suggestions? Y'know, to make
it more perl-y?

Thanks!
Rich
 
T

Tad McClellan

Rich Grise said:
I'm going through a file of the format:


[ snip data ]


I don't think we need to see the data, as I don't think you
are asking about how to get the 3 values, but rather how to
put the 3 values somewhere else once gotten?

If so, then where the 3 values come from is not relevant.

which are kind of name-value pairs where "ItemX" is a name
and item "ValueX" is a value.


That suggests using a hash data structure.

So, I've got it going through the file, picking lines
and building a little array: ($item1value,$item2value,$item3value),


That is a "list" not an "array".

Now, I can rearrange the printf to put them in any order in
the output, so I could run stdout thru sort and sort by
any field, but then I'd have to rearrange that output
again.


You are right to not like that idea. :)

You should be able to get whatever you need right out of Perl.

You can do sorting in native Perl you know.

So, obviously, I need to store these 3 items in an array,
like @ITEMS[$count] = ($a,$b,$c); and then increment $count,
is that right?
^^^^

Which "that" is that?

Yes, you need to store 3 items in an array.

No, that code is not going to get it done.

Or would it make more sense to make a hash,


Let me pull out a quote I've enshrined on my hard disk:

Message-ID: <[email protected]>

I don't know what your original problem is,
but I suggest to use a hash. --Rafael Garcia-Suarez

like %ITEMS{"$a"} = ($b,$c); , since in a way, $a is a name
^ ^
^ ^ a useless use of quotes.

Don't use quotes where you don't need quotes.

that values $b and $c are associated with.


You need some kind of multi-level data structure, but I can't
make enough sense of your description thus far to suggest one.

Also, in my
reading, ISTR something about adding items to an array by
just adding them, and let perl take care of indexing, or


perldoc -f push

was that just hashes? Anyway, I'm reluctant to make a hash,
because can you then sort it on one of the item values? i.e.


Of course you can.

It is a Frequently Asked Question.

Please do not ask Frequently Asked Questions, just read the answer
first, _then_ ask questions.


perldoc -q sort

How do I sort a hash (optionally by value instead of key)?

sort "%ITEMS{"$a"} = ($b,$c)" on $b?


We can't really talk about it accurately with your psuedo-Perl, so
I'll attempt to translate what I think you mean into Perl:

Load up an HoL:

$items{$a} = [ $b, $c ]; # this is inside of a loop, many such assignments

later, sort by the 1st field ($b) like in the FAQ answer:

# untested
@keys = sort {
$items{$a}->[0] cmp $items{$b}[0]
} keys %hash; # and by value

I guess the simple straightforward, non-arcane, way is:
$count = 0;
while (<>) {
# [get the 3 variables]
@items[$count++] = ($a, $b, $c);
}


Now that is a _different_ multi-level data structure.

Load up an LoL:

push @items, [ $a, $b, $c ]; # this is inside of a loop too

and sort by the 2nd field

# untested
@keys = sort {
$a->[1] cmp $b->[1]
} @items; # and by value

if anyone has any suggestions?


Please check the Perl FAQ *before* posting to the Perl newsgroup.

Y'know, to make
it more perl-y?


Learn about multi-level data structures in Perl:

perldoc perlreftut
perldoc perlref
perldoc perllol
perldoc perldsc
 
B

Bob Walton

Rich Grise wrote:

....

I'm going through a file of the format:

Item1:<discard>Value1<discardthis>
<discard>
<discardItem2<discard>Value2<discard>
<discard>
<discard>Value3<discard>Item3<discard>
Item1:<discard>Value4<discardthis>
<discard>
<discardItem2<discard>Value5<discard>
<discard>
<discard>Value6<discard>Item3<discard>

which are kind of name-value pairs where "ItemX" is a name
and item "ValueX" is a value.

So, I've got it going through the file, picking lines
and building a little array: ($item1value,$item2value,$item3value),
which it printfs.

Now, I can rearrange the printf to put them in any order in
the output, so I could run stdout thru sort and sort by
any field, but then I'd have to rearrange that output
again.

So, obviously, I need to store these 3 items in an array,
like @ITEMS[$count] = ($a,$b,$c); and then increment $count,
is that right? Or would it make more sense to make a hash,


Well, not quite. You want to store a reference to ($a,$b,$c) in @ITEMS,
like:

$ITEMS[$count]=[$a,$b,$c];

See:

perldoc perllol
perldoc perlref

for info on this. Note the use of $ITEMS -- you are dealing with a
single subscript, not a list of subscripts, so the value you are storing
is a scalar, not an array, so you need $, not @. @ will work, but will
treat the assignment as an array slice assignment, making the code
harder to follow. Also note the use of [...], which generates a
reference to an anonymous array.

like %ITEMS{"$a"} = ($b,$c); , since in a way, $a is a name
that values $b and $c are associated with. Also, in my
reading, ISTR something about adding items to an array by
just adding them, and let perl take care of indexing, or
was that just hashes? Anyway, I'm reluctant to make a hash,
because can you then sort it on one of the item values? i.e.
sort "%ITEMS{"$a"} = ($b,$c)" on $b?

---------------^--^
Useless use of " -- see:

perldoc -q quoting

for why.

Sorting on hash values is a FAQ:

perldoc -q sort

You might also look up the Schwartzian Transform, as it can offer a
considerable efficiency improvement on hash sorts over "normal" sort code.

I guess the simple straightforward, non-arcane, way is:
$count = 0;
while (<>) {
# [get the 3 variables]
@items[$count++] = ($a, $b, $c);


$items[$count++] = [$a, $b, $c];

Also, I note that you changed from ITEMS to items -- Perl is case
sensitive, and cares about that.

}

But ISTVR something about #items, but don't know where to
look for it, if anyone has any suggestions? Y'know, to make
it more perl-y?


More Perl-y would be:

my @items;
while(<>){
#get the three variables
push @items,[$a,$b,$c];
}

You could also consider storing a reference to an anonymous hash rather
than an anonymous array in @items, which would look like:

...
push @items,{Item1=>$a,Item2=>$b,Item3=>$c};
...

Doubtful there are advantages to that given your input above, but I
don't know exactly what you plan to do with your data structure. It
could be clearer to refer to $items[$n]{Item1} than referring to
$items[$n][0] for an "Item1" value, for example.


....
 
B

Ben Morrow

Quoth "Rich Grise said:
So, obviously, I need to store these 3 items in an array,
like @ITEMS[$count] = ($a,$b,$c); and then increment $count,
is that right? Or would it make more sense to make a hash,
like %ITEMS{"$a"} = ($b,$c); , since in a way, $a is a name
that values $b and $c are associated with.

When asking 'should I use an array or a hash', the answer is use an
array if you need to preserve the original order, a hash if you just
need to look up items given one of the others. If you need both you can
use Tie::IxHash from CPAN.

If your problem is really as simple as sorting on the second field and
printing, I'd use a hash like this:

my %data;

while ( more_data() ) {
# set $one, $two, $three
# see the $a and $b in perldoc perlvar for why you shouldn't
# use those particular two names

$data{$two} = [ $one, $two, $three ];
}

$, = ", ";
$\ = "\n";

print @{$data{$_}} for sort keys %data;

I have to say, though, that I cannot for the life of me work out how you
get triples out of the data you showed...

Ben
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,740
Latest member
JudsonFrie

Latest Threads

Top