How to join two array entries in perl - arrays

I have one array, and I want to join the 5th and the 6th entry of it!
Like: #array(1,2,3,4,5,6,7,8,9) should be #array(1,2,3,4,56,7,8,9)
How could i achieve that? I've just found in the internet how to merge two arrays, but not two entries...
Thanks in advance.
Best regards, John.

The simplest approach is to use splice, along with an array slice.
use warnings;
use strict;
my #array = (1,2,3,4,5,6,7,8,9);
splice #array, 4, 2, join('', #array[4,5]);
print "#array";

my #a = (1,2,3,4,5,6,7,8,9);
my #b = (#a[0..3], join('',#a[4..5]), #a[6..8]);
print "#b\n"; # <---- prints: 1 2 3 4 56 7 8 9

Related

How to get the index of the maximum element in an array?

I want to find the maximum value in an array and print his index.
I wrote this for print the maximum value; it works but I don't know how print the index.
use feature "say";
use List::Util qw(max);
#x=qw(10 -2 -48 -5 7 34 28);
say "valore massimo: ".max #x;
The core List::Util comes with an almighty reduce, which can be used to direclty work out all kinds of results
use warnings;
use strict;
use feature 'say';
use List::Util qw(reduce);
my #x = qw(10 -2 -48 -5 7 34 28);
my $max_idx = reduce { $x[$a] > $x[$b] ? $a : $b } 0..$#x;
say "Maximal value of $x[$max_idx] is at index $max_idx";
Can wrap this in a simple function, to have a clear name for the operation (max_idx or something, and which can return both the element and its index, perhaps only in list context). Libraries for list utilities often merely package reduce expressions into handy functions.
A utility with the above functionality is max_by from List::UtilsBy, as shown in Silvio Mayolo's answer (but we don't have to make an array of indices first).
A nitpick but I 'd like to mention. The list of (obviously) numbers given in the question as qw(10 -2 -48 -5 7 34 28) is a list of strings ("words"), as qw operator builds things.
These are treated as numbers once they are used that way, as normally done by the interpreter, and all is well. However, since they are clearly to be numbers I prefer to introduce them as such
my #x = (10, -2, -48, -5, 7, 34, 28);
A touch more typing but I find that it conveys the intent more clearly. Again, by all means this is of no consequence for most (any?) code.
List::UtilsBy provides the max_by, for getting a maximum according to some other criterion (which could be another list).
use 5.010;
use List::UtilsBy qw/max_by/;
my #x = qw(10 -2 -48 -5 7 34 28);
my #indices = (0..#x-1);
say max_by { $x[$_] } #indices;
Generally, if you're doing nontrivial list manipulation in Perl, I recommend installing List::AllUtils, which is an all-in-one package including List::Util, List::SomeUtils, and List::UtilsBy.
For a small task such as this, you don't really need to use external libraries.
use strict;
use warnings;
use feature 'say';
my #x = (10, -2, -48, -5, 7, 34, 28);
my $max = 0; # first index is the max
for (0 .. $#x) {
if ($x[$_] > $x[$max]) {
$max = $_;
}
}
say "#x";
say "Max number is $x[$max] with index $max";
Output:
10 -2 -48 -5 7 34 28
Max number is 34 with index 5
Just loop over the indexes, check the values and save the index with the highest number.
The task you are doing is absolutely basic and crucial to programming. If you start to learn programming, you should be able to come up with a solution on your own.
Yes, there exists nice modules that make this task a lot more elegant, but if you are learning to programming, you should come up at least with a solution like this, ON YOUR OWN!
printf "%d\n", max_index(10,3,22,5,4,11,33); # prints 6
printf "%s\n", max_index(34,21,100,12,9); # prints 2
sub max_index {
my ( #list ) = #_;
my $max_index = 0;
my $max_value = shift #list;
my $idx = 0;
for my $current ( #list ) {
$idx++;
if ( $current > $max_value ) {
$max_index = $idx;
$max_value = $current;
}
}
return $max_index;
}
Homework:
What happens if you pass no element to the function? What should be returned?
Make it work with an array reference.
Use a classic for-loop for (..., ..., ...) { ... }, and don't use shift.
What happens if you pass strings to it, instead of numbers?
Do you know a solution to problem 4?
In situation if you would prefer to use only Perl due restriction on Perl module installation - to find index of maximum value in an array you could use following algorithm:
assume that first element in the array has $max value
compare following array elements with $max
store index and value for max element if satisfices the condition
use strict;
use warnings;
use feature 'say';
my #arr = qw(10 -2 -48 -5 7 34 28);
my($ind,$max) = find_max(\#arr);
say "arr[$ind] = $max";
sub find_max {
my $arr = shift;
my($i,$max)=(0,$arr->[0]);
for( 1..$#{$arr} ) {
($i,$max) = ($_,$arr->[$_]) if $max < $arr->[$_];
}
return ($i,$max);
}
Output
arr[5] = 34
You can try the following code
use List::Util qw(max);
my #x = qw(10 -2 -48 -5 7 34 28);
my ($index) = ( grep { $x[$_] eq max(#x) } 0..$#x );
print "max ", max(#x), " index $index\n";
Output
max 34 index 5

How can I tie an array slice to the original array so all changes that are made to one are made to both?

I need to be able to tie an array slice to the original array in such a way that any changes made to the original array (including removing elements) will also be made to the array slice. Is there a way to do this?
The following example does not work how I want it to, but it is simply there to demonstrate the point I am trying to make.
Example:
my #array = 1 .. 10;
my #slice = #array[3 .. 8];
splice #array, 5, 2;
print "ARRAY: ";
print join ', ', #array;
print "\n";
print "SLICE: ";
print join ', ', #slice;
Output:
ARRAY: 1, 2, 3, 4, 5, 8, 9, 10
SLICE: 4, 5, 6, 7, 8, 9
What I am looking for is a way to tie the slice to the original array so the output would look like this instead:
ARRAY: 1, 2, 3, 4, 5, 8, 9, 10
SLICE: 4, 5, 8, 9
Removing 6 and 7 from the original array would also remove it from the array slice.
How can I achieve something like this?
As has been said, that's a tall order. The short answer is no. A slice creates a copy of the elements.
Perl does have a Tie feature that might be just the trick.
perltie - how to hide an object class in a simple variable
So it fundamentally changes what a variable is behind the scenes. A whole world of possibilities opens up, and your scenario just might be in there.
perltie on perldoc.perl.org
Updated post as requested using Object oriented method. Maintained original response after <========> Line
Here's the object oriented approach as mentioned in comments.
Sample.pm
package Sample;
use strict;
use warnings;
use Exporter qw(import);
use List::MoreUtils qw(first_index);
our #y = qw (3 4 5 6 7 8 9); # Add your method of acquiring #y value here
our #EXPORT = qw (SpliceV2 #y);
## Your Splice Version 2
sub SpliceV2(#) {
my ($position,$length,#x) = #_;
for (my $i=1;$i<=$length;$i++) {
my $removeditem = $x[$position];
my $remove = first_index { $_ eq $removeditem } #y;
splice #x, $position, 1;
splice #y, $remove, 1;
}
return #x;
}
1;
Main script:
#!/usr/bin/perl
use Sample;
my #x = qw(1 2 3 4 5 6 7 8 9 10);
#x = SpliceV2(4,2,#x);
print "X: #x\n";
print "Y: #y\n";
Original post below
<==========>
Assuming the items you are removing are unique like if you are basing it on primary keys of a database, then you can use first_index from List::MoreUtils;
Here's a sample.
use List::MoreUtils qw(first_index);
my #x = qw (1 2 3 4 5 6 7 8 9 10);
my #y = qw (4 5 6 7 8 9);
## Let's say you want to remove 2 items after the 5th index
my $position = 5;
my $length = 2;
## Get the value of items to remove first
for (my $i=1;$i<=$length;$i++) {
my $removeditem = $x[$position];
my $remove = first_index { $_ eq $removeditem } #y;
splice #x, $position, 1;
splice #y, $remove, 1;
}
print "Array X\n";
print "$_," foreach(#x);
print "\nArray Y\n";
print "$_," foreach(#y);
print "\n";
You should get the result you wanted.
Array X
1,2,3,4,5,8,9,10,
Array Y
4,5,8,9,
use strict;
use warnings;
use Data::Dumper;
my #array = 1..10;
my #slice = \#array[3..8];
splice #array, 5, 2;
print "ARRAY: ";
print join ', ', #array;
print "\n";
print "SLICE: ";
print join ', ', #slice;
Output:
ARRAY: 1, 2, 3, 4, 5, 8, 9, 10
SLICE: SCALAR(0x29dcef0), SCALAR(0x29dcf20), SCALAR(0x29dcf08), SCALAR(0x29dcfb0), SCALAR(0x29dcfc, SCALAR(0x29dd058)
Instead removing the items you could assign a zero value to the item (it will assign a zero value in the #slice too, because #slice holds a refference to #array) and then remove the 0's from you #slice and voila, you have your updated #slice with your deleted elements

perl concat 5 arrays on same index

I have five arrays and I tried to write them into one array for several hours now. Strangely it works for the first three arrays but as soon as I add the fourth the indexes are messed up or something. The length of all arrays is the same so it should not be a problem to do it like this.
Examples:
INPUT:
#names = [jeff,george,ringo,chris]
#td = [10/04/2014,11/04/2014,12/04/2014,13/04/2014]
#vct1= [5,6,4,0]
#vct2= [1,1,2,2]
#vct3= [6,0,1,5]
Expected OUTPUT:
#ffo = [jeff 10/04/2014 5 1 6
george 11/04/2014 6 1 0
ringo 12/04/2014 4 2 1
chris 13/04/2014 0 2 5]
Here is my code for merging:
for ($i=0;$i<#vct1;++$i) {
push(#ffo,trim(#names[$i])."\t".trim(#td[$i])."\t".trim(#vct1[$i])."\t".trim(#vct2[$i]).trim(#vct3[$i])."\n");
}
I tried List::MoreUtils with zip and
#ffo = map { $names[$_], $td[$_], $vct1[$_], $vct2[$_], $vct3[$_], } 0 .. $#names;
but it did not work. Does anyone know why?
If I use the arrays like this it works:
#names = qw(jeff george ringo chris);
#td = qw(10/04/2014 11/04/2014 12/04/2014 13/04/2014);
#vct1 = qw(5 6 4 0);
#vct2 = qw(1 1 2 2);
#vct3 = qw(6 0 1 5);
for ($i=0;$i<#names;++$i) {
print #names[$i]."\t".#td[$i]."\t".#vct1[$i]."\t".#vct2[$i]."\t".#vct3[$i]."\n";
}
OUTPUT:
jeff 10/04/2014 5 1 6
george 11/04/2014 6 1 0
ringo 12/04/2014 4 2 1
chris 13/04/2014 0 2 5
I'll take a wild stab at answering this, although you have not supplied enough information for me to be sure. This code:
#names = [jeff,george,ringo,chris]
#td = [10/04/2014,11/04/2014,12/04/2014,13/04/2014]
#vct1= [5,6,4,0]
#vct2= [1,1,2,2]
#vct3= [6,0,1,5]
Does not compile. There are several things wrong with it:
It lacks semi-colons ; at the end of the lines,
The values are not quoted, i.e. "jeff","george", the string 10/04/2014 will be interpreted as three numbers being divided and will become 0.00124...,
You are assigning a single value to the arrays: an anonymous array reference [ ... ]
My guess is that you really have something like this:
#names = ["jeff","george","ringo","chris"];
#td = ["10/04/2014","11/04/2014","12/04/2014","13/04/2014"];
#vct1= [5,6,4,0];
#vct2= [1,1,2,2];
#vct3= [6,0,1,5];
And you do not realize that this will create a two-dimensional array, where the first element in each array contains the arrays you want. I.e.: $names[0][0] contains "jeff", and so on.
You say that it works when you use qw(), which is a function that will create a list of quoted arguments (mnemonic: QuoteWords). These two are equivalent statements:
#names = qw(jeff george ringo chris);
#names = ("jeff", "george", "ringo", "chris");
So... use either of these ways to assign values to your arrays.
And also, you should always use
use strict;
use warnings;
As they will tell you about all the mistakes you make. I am guessing if you add them to your code now, you will get quite a few warnings and fatal errors. Which is a good thing. Not knowing about what you did wrong does not help improve your code.
In your original code, you had this:
#names = [jeff,george,ringo,chris]
#td = [10/04/2014,11/04/2014,12/04/2014,13/04/2014]
#vct1= [5,6,4,0]
#vct2= [1,1,2,2]
#vct3= [6,0,1,5]
But you should not declare arrays with the [ ] operator, unless you are interested in an array of anonymous arrays.
Thus, #td, for example, contains only a single element, which is a reference to an anonymous array:
#! /usr/bin/perl
use strict;
use warnings;
my #td = [10/04/2014,11/04/2014,12/04/2014,13/04/2014];
foreach my $element (#td) {
print "$element\n"; # Prints a single element ARRAY(0x7f8e108070d0)
}
print "Size of \#td: ", scalar(#td), "\n"; # Prints 1
You avoid this problem when you use the qw operator which knows to return an array, not an array reference, containing the elements you want.
You first method should work, like this:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my #names = qw(jeff george ringo chris);
my #td = qw(10/04/2014 11/04/2014 12/04/2014 13/04/2014);
my #vct1= qw(5 6 4 0);
my #vct2= qw(1 1 2 2);
my #vct3= qw(6 0 1 5);
my #ffo;
for (my $i = 0; $i <= $#names; $i++) {
push #ffo, join("\t", $names[$i], $td[$i], $vct1[$i], $vct2[$i], $vct3[$i]);
}
print Dumper(\#ffo);
Running:
$VAR1 = [
'jeff 10/04/2014 5 1 6',
'george 11/04/2014 6 1 0',
'ringo 12/04/2014 4 2 1',
'chris 13/04/2014 0 2 5'
];

How to compare two arrays in Perl

I have two arrays. I want to find what elements are in the second but not the first, and what elements are in the first but not the second.
Is there any way with out writing multiple loops?
Each array is something like this $array_2d_1
0 ARRAY(0x9929210)
0 ARRAY(0x98df3d8)
0 71
1 22
2 15
3 10
4 51
1 ARRAY(0x9934900)
0 91
1 82
2 28
3 11
4 91
You can use the module List::Compare for this task:
use strict;
use warnings;
use List::Compare;
my #arr1 = qw/5 8 12 42 99 10/;
my #arr2 = qw/10 20 12 18 99 10/;
my $lc = List::Compare->new( \#arr1, \#arr2 );
my #arr1Only = $lc->get_Lonly;
print "\#arr1 only: #arr1Only\n";
my #arr2Only = $lc->get_Ronly;
print "\#arr2 only: #arr2Only\n";
Output:
#arr1 only: 42 5 8
#arr2 only: 18 20
Hope this helps!
You can't avoid looping. This solution has four loops, but they're not nested.
my %a1 = map { $_ => 1 } #a1;
my %a2 = map { $_ => 1 } #a2;
my #missing_from_a1 = grep !$a1{$_}, #a2;
my #missing_from_a2 = grep !$a2{$_}, #a1;
I think you are looking for something like set implementation in perl right. In standard perl there is no set implementation and here is the module in cpan that can achieve what you are trying to solve set. So, we have to find out a way that we can create unique element out of the array, and hash keys in perl is unique. By using hash implementation we can achieved the set implementation. More details you can look up here :
Set Implementation
To take the set difference between two sets, there must be loops involved somewhere. I am assuming you want to avoid writing out the loops every time you need to compute the set difference instead of having an unhealthy aversion to loops.
One simple way would be to abstract away the operation into a subroutine:
#!/usr/bin/env perl
use strict;
use warnings;
main();
sub main {
my #x = (1, 2, 3, 4, 5);
my #y = (3, 5, 7, 8, 9);
for my $sets ( ([\(#x, #y)], [\(#y, #x)]) ) {
print "#{ set_diff( #$sets ) }\n";
}
}
sub set_diff {
my $x = shift;
my %y = map { $_ => undef } #{ $_[0] };
return [ grep not( exists $y{$_} ), #$x ];
}
There are also a number of set implementations on CPAN.

perl - how do you extract all elements of an array except the last?

I need to extract all elements in an array except the last and store them in a scalar for later use.
At first, I thought this would be possible using array slices, but it appears that you cannot count backwards.
For example:
my $foo = ($bar[0..-2]);
or
my $foo = ($bar[-2..0]);
Any help would be greatly appreciated as this is starting to drive me insane, and I have been unable to find a solution elsewhere or by experimenting.
Oskar
my $foo = join ',', #bar[0..$#bar-1];
will concatenate (by comma) all elements of the array #bar except the last one into foo.
Regards
rbo
my #foo = #bar;
pop #foo;
or
my #foo = #bar[ -#bar .. -2 ];
or if it's ok to change #bar, just
my #foo = splice( #bar, 0, -1 );
#foo = #bar[0 .. $#foo - 1];
If you want to create a head-scratcher:
my #x = (1, 2, 3);
print "#x[-#x .. -2]";
This will store all array elements, except for the last, into a scalar. Each array element will be separated by a single space.
use strict;
use warnings;
my #nums = 1 .. 6;
my $str = "#nums[0 .. $#nums - 1]";
print $str;
__END__
1 2 3 4 5
Don't you really want to store the elements into another array? If you store them in a scalar, it can be problematic to retrieve them. In my example above, if any element of the array already had a single space, you would not be able to properly reconstruct the array from the scalar.

Resources