Modification of non-creatable array value attempted, subscript -4 - perl

I am newbie to perl. My script was running for months together and now it is causing a problem and it wont send an email. The script actually sends 2 different graphs (line and bar) of the total number cases per week and its average.
This is the line that is throwing error.
$graph->set_legend(#week_start_dates[-4..-1]);
Error message-Modification of non-creatable array value attempted, subscript -4
Is it something to do with perl where you cannot increase the index on left.(-4,-5) etc.
Any thoughts much appreciated.Thanks

Yes, because subroutine parameters are aliases to the actual value, the value has to exist, and while it will create positive indexes if they don't exist, it doesn't lengthen the array to create negative indexes, because that would change the meaning of other indexes that do exist.
You can see this simply with:
perl -wle'#x = 1..3; sub{}->(#x[-4..-1])'
Modification of non-creatable array value attempted, subscript -4 at -e line 1.
So you should figure out why there are less than four week_start_dates.
Or if having less than four week_start_dates is acceptable, you could use the following:
#week_start_dates > 4 ? #week_start_dates[-4..-1] : #week_start_dates

Related

How to access last argument in PowerShell script (args)

I have following code:
foreach ($arg in $args) {
Write-Host "Arg: $arg";
$param1=$args[0]
}
Write-host "Number of args: " $args.Length
write-host Last Arg is: "$($args.count)"
I get this, when I run it:
./print_last_arg.ps1 a b c
Arg: a
Arg: b
Arg: c
Number of args: 3
Last Arg is: 3
What I would like to have is name of last argument, so:
Last Arg is: 3
should be:
Last Arg is: c
Sorry for such a stupid question but I am totally begginer in PS and cannot google the result...
PowerShell supports negative indices to refer to elements from the end of a collection, starting with -1 to refer to the last element, -2 to the penultimate (second to last) one, and so on.
Therefore, use $args[-1] to refer to the last argument passed.
For more information, see the conceptual about_Arrays help topic.
Note that you can also use the results of expressions as indices; e.g., the equivalent of $args[-1] is $args[$args.Count-1] (assuming the array has at least one element).
Additionally, you may specify multiple indices to extract a sub-array of arbitrary elements. E.g., $args[0, -1] returns a (new) array comprising the input array's first and the last element (assuming the array has at least two elements).
.., the range operator is particularly useful for extracting a range of contiguous elements. E.g., $args[0..2] returns a (new) array comprising the first 3 elements (the elements with indices 0, 1, and 2).
You can even combine individual indices with ranges, courtesy of PowerShell's + operator performing (flat) array concatenation.
E.g., $args[0..2 + -1] extracts the first 3 elements as well as the last (assumes at least 4 elements).
Note: For syntactic reasons, if a single index comes first in the index expression, you need to make it an array with the unary form of , the array constructor operator, to make sure that + performs array concatention; e.g., $args[,-1 + 0..2] extracts the last element followed by the first 3.
Pitfall: Combining a positive .. start point with a negative end point for up-to-the-last-Nth-element logic does not work as intended:
Assume the following array:
$a = 'first', 'middle1', 'middle2', 'last'
It is tempting to use range expression 1..-2 to extract all elements "in the middle", i.e. starting with the 2nd and up to the penultimate element - but this does not work as expected:
# BROKEN attempt to extract 'middle1', 'middle2'
PS> $a[1..-2]
middle1
first
last
middle2
The reason is that 1..-2, as a purely arithmetic range expression, expanded to the following array (whose elements happen to be used as indices into another array): 1, 0, -1, -2. And it is these elements that were extracted: the 2nd, the first, the last, the penultimate.
To avoid this problem, you need to know the array's element count ahead of time, and use an expression to specify the end of the range as a positive number:
# OK: extract 'middle1', 'middle2'
# Note that the verbosity and the need to know $a's element count.
PS> $a[1..($a.Count-2)]
middle1
middle2
Unfortunately, this is both verbose and inconvenient, especially given that you may want to operate on a collection whose count you do not know in advance.
GitHub issue #7940 proposes a future enhancement to better support this use case with new syntax, analogous to C#'s indices-and-ranges feature, so that the above could be written more conveniently with syntax such as $a[1..^1]

Why does this line return sum of integers 1-10?

I'd like to understand how unpack is returning the sum in the given perl one-liner.
I've looked at pack man page and mostly understood that it is simply formatting the given array into a scalar of ten doubles.
However, I couldn't find proper documentation for unpack with %123. Looking for help here.
print unpack "%123d*" , pack( "d*", (1..10));
This line correctly outputs 55 which is 1+2+3+...+10.
From perldoc -f unpack:
In addition to fields allowed in pack(), you may prefix a field with a % to indicate that you want a <number>-bit checksum of the items instead of the items themselves.
Thus %123d* means to add all the input integers 1..10 and then take the first 123 bit of this result in order to construct the "<number>-bit checksum". Note that %8d* or just %d* (which is equivalent to %16d*) would suffice too given that the sum is small enough.

Using strmatch in a loop

Can I do the something below coded using or without loop?
Actually I am having a character array comprising of unique words more than 5000 and other array comprising of approx 3000 words. I want to search each word in my array named as word in other array named as uniques and wish to create a feature vector i.e. values 1 if exists and 0 if doesn't.
I am doing the following..
load 'uniques' %uniques={'alpha','ok',abc'};
fid=fopen(myfilename);
words=textscan(fid,'%s');
fclose(fid);
word=words{1,1}; %word={'good','bad',anywhere','countries','ok',done','abc'}
for i=1:size(uniques,2)
ind=strmatch(word(i), uniques, 'exact');
end
Now, seeing above as examples before uniques and word arays, my system must return 0 for good as good is not there in uniques and same 0 values but 1 for ok because it does exist in uniques. All in all, I must have in the end, {0,0,0,0,1,0,1} ..
After I run, it gives me ind=[]
Please guide
You have described the exact functionality of the ismember function:
ismember(word, uniques);
as an aside, this is what #nkjt was saying about fixing your loop:
for i=1:size(word,2)
ind(i)=strmatch(word(i), uniques, 'exact');
end
But this loop is unnecessary since Matlab has this as a built in function

What does this piece of Perl code do in laymans terms?

Found this inside a loop. I've read up about splice but it just confused me more.
I'm not familiar with Perl, but am trying to translate an algorithm to another language.
my $sill = splice(#list,int(rand(#list)),1);
last unless ($sill);
To be more specific: What will be inside $sill if it doesn't exit the loop from the last?
Thanks for any help!
This randomly removes one element from the array #list. That value is assigned to $sill. If that was a false value, the enclosing loop (not shown) is broken out of.
splice takes an array, an offset, and a length, plus a replacement list. If the replacement is omitted, the elements are deleted.
The length is constant (1 element), but the offset is calculated as a random integer smaller between 0 and the length of #list.
That means :
remove a random element from the array list (0 -> numbers of element of the list) and
assign the sill variable with the removed element (pop() like) and
exit the loop if sill variable is false
See http://perldoc.perl.org/functions/splice.html

Error: Can't take log of -9.4351e+0.007

I am creating a mini search engine using Perl.While doing so I am using a formula with log to the base 10. However for some value I am getting an error:
Can't take log of -9.4351e+0.007.
It is impossible to track where I am getting this error from. I just want to ignore this case. How can this be handled in Perl. Subroutine for finding log to the base 10 is like this:
sub log10 {
my $n=shift;
return log($n)/log(10);
}
So probably i am looking for a check which says if so and so value dont find log.
You cannot take the log of negative numbers.
See Wolfram MathWorld for more details.
Apart from the value being negative, the string -9.4351e+0.007 is not a valid number as the exponent part of a floating-point constant can be only an integer.
You must be passing strings to your log10 function as Perl would not complain about a number in this format.
You need to look at the source of these values as something is going wrong before your function is called, and it will probably give you incorrect results even for those values that can be passed to log without error.
"ln y" means "find the x where ex equals y".
e is a positive number (near 2.17828), so no matter how many times you multiply e with itself, you'll never get a negative number.
You cannot find the log of negative numbers.
As Borodin also points out that -9.4351e+0.007 isn't recognized as a number by Perl.
>perl -wE"say 0+'-9.4351e+0.007'"
Argument "-9.4351e+0.007" isn't numeric in addition (+) at -e line 1.
-9.4351