Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Combining Arrays

Status
Not open for further replies.

lmbylsma

Programmer
Nov 11, 2003
33
US
So I have this script that produces 2 different arrays by reading data from a file, the 2 arrays look something like this:

Array #1:

4.12 0
5.13 1
6.14 0

Array #2

16.37 0????" 8 0 0 0
19.26 0????" 9 0 0 0
22.21 0????" 0 0 0 0

So what I want to do is combine them into one array that looks like this:

Combined Array:

4.12 0 16.37 0????" 8 0 0 0
5.13 1 19.26 0????" 9 0 0 0
6.14 0 22.21 0????" 0 0 0 0

I thought I could do something like:

@Combined = join(@Array1, @Array2);

But that doesn't work.

And at some point, either before or after combining I would like to get rid of some of those columns...the ones with the ????, and the ones with only 0's so it would then look like this:

4.12 0 16.37 8
5.13 1 19.26 9
6.14 0 22.21 0
 
First, a few things to read up on in perldoc:
perllol - List of Lists, multidimensional array structures
splice - a function used to take chunks in or out of any place in an array
map - a function that performs an operation on each element of a list

A short example for you:
Code:
my @arr1 = (
	[qw/4.12      0/],
	[qw/5.13      1/],
	[qw/6.14      0/],
);

my @arr2 = (
	[qw/16.37    0????"  8   0   0   0/],
	[qw/19.26    0????"  9   0   0   0/],
	[qw/22.21    0????"  0   0   0   0/],
);

#be sure they have the same number of rows
#make a new array making a new row out of tacking on
#arr2's rows at the end of arr1's rows
my @arr3 = ();
for(my $i = 0; $i < @arr1; $i++)
{
	push @arr3, [@{$arr1[$i]}, @{$arr2[$i]}];
}

#column index 3 looks bad, so splice it out on each row
my @arr4 = map { splice(@$_,3,1) && $_ } @arr3;

----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Ok I understand the second part of what you said, but I don't understand what's going on here:

my @arr1 = (
[qw/4.12 0/],
[qw/5.13 1/],
[qw/6.14 0/],
);

my @arr2 = (
[qw/16.37 0????&quot; 8 0 0 0/],
[qw/19.26 0????&quot; 9 0 0 0/],
[qw/22.21 0????&quot; 0 0 0 0/],
);


What's the qw/ / do?

I don't want to make the arrays from scratch, I want to work from the arrays I already have. What happens at the end of the script I already have is I get 2 Arrays, and each line of the array is a string I guess, the elements aren't broken down, because the array was made by reading lines of a file and putting 1 line per place in the array. So I guess what I want to do first is split up the &quot;words&quot; in each line in the array into separate elements and get rid of the spaces so I can work with it. Maybe &quot;split&quot; would be useful for this?


I tried incorporating something like your suggestion here:

for(my $i = 0; $i < @arr1; $i++)
{
push @arr3, [@{$arr1[$i]}, @{$arr2[$i]}];
}

into my code to put the 2 arrays side by side as they are, without breaking up the elements. But what I get as output when I try to print the array is:

ARRAY(0x8155a6c)
ARRAY(0x8155a0c)
ARRAY(0x8155988)
etc.

Does my array have to be in a particular format for it to work?

Thanks for your help,

-Lauren
 
Sorry, I kind of assumed you were working with a list of lists since the example data you provided looks like a two dimensional array. Have a look at &quot;perldoc perllol&quot; for general syntax and the like. perldsc perlref and perlreftut might be helpful, too.

qw/red blue/ just breaks the string on whitespace and returns a lit of words. It's the same as ('red','blue'). The [ ] around it makes an anonymous array and stores the reference. The reason you get ARRAY(0xhex) is because you're printing the references and not the values (again, check perllol).

If you want to keep your current method of just strings, you could say something more like this:
Code:
#make the combined array (from your originals, not mine)
for(my $i = 0; $i < @arr1; $i++)
{
    push @arr3, &quot;$arr1[$i]\t$arr2[$i]&quot;;
}

#remove the pesky 0????&quot;
s/\Q0????&quot;\E\t// for(@arr3);
Lists of lists and other combined data strcutures are immensely useful, but if you don't want to learn and use them right now, the above should work alright, though I didn't test it.

----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Thanks for your help, that did work to put my arrays together and remove the ???? column. But how to remove the 3 columns at the end with the 0's...I can't just say to take out whatever is a 0 with spaces next to it because the 4th column contains numbers from 0-9, so I don't want those 0's removed. I tried doing something like this:

for (@Final){split(/ /,$_)}; #splits it up where the spaces are into separate elements

@Final=splice(@Final, -$3); #removes last 3 elements

Which as I understood it, should remove the last 3 items from the array..which I would think would be the 3 columns with the 0's. But instead nothing happens, it prints out the same as before.


Also, I don't understand why when I printed the array using the former code it was printing out references instead of the actual values, because I told another array to print in the same exact way and that one printed out fine, and I thought the arrays themselves were pretty similar in structure - both contained a list of strings.

So here's what the output is looking like at this point:


1.1 1 3.92090 9 0 0 0
2.1 0 16.37657 8 0 0 0
3.1 1 19.26123 9 0 0 0
4.1 0 16.37657 8 0 0 0
5.1 1 19.26123 9 0 0 0
6.1 0 16.37657 8 0 0 0


Thanks again for your help.

-Lauren
 
You could add this in the other for loop that took out the ????:
Code:
s/(\t\d){3}$/;
It looks for a tab followed by a number, repeated three times, and anchored to the end of the line.

I feel like if you're going to leave them as strings in your array, you should treat them like strings instead of converting to and from an array all the time. But making it a proper list of lists would be the &quot;best&quot; way to do it.

It sounds like you need to sit down with a book or some builtin documentation and read about how things work in perl. Things like
Code:
for (@Final){split(/ /,$_)};
will do absolutely nothing. Split returns an array, but you're using it in null context and not saving that return value at all. And even if you returned an array ref of the split values and stored it as each element in @Final, the splice statement works off @Final's elements, which are rows. So at best, it'd chop the last three rows off, not the last three columns.

----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
I read the documentation, but I'm just not understanding the different types of arrays and why it seems you can only use certain functions on certain types of arrays. I'm new to programming and the documentation assumes you know all about programming already and doesn't explain everything.

I don't understand why an array of strings is different from a list of lists. I understand from the documentation how to refer to things when you have a lists of lists, but of course its not working on my array because mine is not in this format. So if someone could just help me figure out how to get it into the lists of lists format, I think I can take it from there, since then I know how to refer to specific elements in my array and then I can work with it.

So the array I want to do this with looks like this:

1.1 1 3.92090 9 0 0 0
2.1 0 16.37657 8 0 0 0
3.1 1 19.26123 9 0 0 0
4.1 0 16.37657 8 0 0 0
5.1 1 19.26123 9 0 0 0
6.1 0 16.37657 8 0 0 0


And each one of those lines is saved as a string in the array. I want to break it up the elements so I can refer to them separately.


 
A delimited string is different from a list, but the string can easily be split on its delimiting pattern (like tabs or spaces) and be made into a list.
Code:
#split each row on a pattern, here one or more whitespace elements /\s+/
#and have map return a reference to each row [ ]
@Final = map { [split /\s+/] } @Final;

#access elements like this
my $item = $Final[1][3];           #second row [1] fourth column [3]
my @row  = @{$Final[0]};           #array of the first row
my @col  = map { $_->[4] } @Final; #array of the fifth column

#print the matrix of data kind of prettily
foreach my $row_ref(@Final)
{
	foreach my $element (@$row_ref)
	{
		#print each element as a string taking up 10 places (space padded)
		printf &quot;%10s&quot;, $element;
	}
	print &quot;\n&quot;;
}
Sorry to harp about documentation, but it really is good stuff. Lots of good examples and descriptions. Sure, I will admit that it assumes a bit of programming knowledge, but it really has to in order to be useful. If you want, perlintro assumes much less and provides a good overview with links to further details:
----------------------------------------------------------------------------------
...but I'm just a C man trying to see the light
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top