PowerShell Math Problem? - math

function other3($x, $y)
{
$tmp = $x + $y
return $tmp
}
$x = 5
$y = 10
$a = other3($x, $y)
Write-Host $a
Keeps returning 5 10 when it should be returning 15, what's the deal?

To call other3 with two parameters, drop the parenthesis "()" e.g.
$a = other3 $x $y
The way you're currently calling it, actually passes one parameter, an array with two elements, i.e. 5 and 10. The second parameter is empty (probably defaults to null), meaning the addition does nothing and you simply return the $x parameter.

You're passing a list (5,10) to the parameter $x and $null to $y.
When the function adds $null to the list, you just get the list back.
Adding some write-host statements to the function should make this clear:
function other3($x, $y)
{
$tmp = $x + $y
write-host "`x=($x)"
write-host "`y=($y)"
return $tmp
}
$x = 5
$y = 10
$a = other3($x, $y)
Write-Host $a

Related

Recursive TCL proc without explicit return

I am writting a simple "proc" to calculate the factorial. I would like to understand why my function does not work without the return statement.
According to TCL docs, functions that are defined without explicit "return",
return the value of the last executed command in its body.
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
return [expr {[fac $n ] * $n}]
}
puts [fac 5] # ans 24
When the "return" is removed, I get the following error message:
invalid command name "1"
while executing
"[expr {[fac $n ] * $n}] "
(procedure "fac" line 7)
invoked from within
I expected that without the explicit "return", the function should return 24 as well.
Your expectation is correct. But you have square brackets around expr procedure in the last line. It is:
[expr {[fac $n] * $n}]
This means for the interpreter: 1) execute expr procedure with given argument; 2) execute the result of expr procedure. Because of this, the interpreter tries to execute procedure 1 that doesn't exist and you receive an error.
To fix this error - just remove square brackets from the last line:
proc fac { n } {
if { $n == 1 } {
return 1
}
puts $n
set n [expr {$n - 1}]
expr {[fac $n ] * $n}
}

What's the equivalent of R's ifelse in Perl PDL

I am new to PDL. R's ifelse() method can do conditonal element selection. For example,
x <- c(1,2,3,4)
ifelse(x%%2, x, x*2)
# [1] 1 4 3 8
Anyone knows how to do this in PDL? I know you can do it like below, but is there any better ways?
pdl(map { $_ % 2 ? $_ : $_*2 } #{$x->unpdl} )
#! /usr/bin/perl
use warnings;
use strict;
use PDL;
my $x = 'PDL'->new([1, 2, 3, 4]);
my $where = ! ($x % 2); # [0 1 0 1]
my $y = $x * ($where + 1);
print $y; # [1 4 3 8]
or, shortly
my $y = $x * ( 2 - $x % 2 );
Answering the question myself. It can be something like this,
use PDL;
sub ifelse {
my ( $test, $yes, $no ) = #_;
$test = pdl($test);
my ( $ok, $nok ) = which_both($test);
my $rslt = zeros( $test->dim(0) );
unless ( $ok->isempty ) {
$yes = pdl($yes);
$rslt->slice($ok) .= $yes->index( $ok % $yes->dim(0) );
}
unless ( $nok->isempty ) {
$no = pdl($no);
$rslt->slice($nok) .= $no->index( $nok % $no->dim(0) );
}
return $rslt;
}
my $x = pdl( 1, 2, 3, 4 );
say ifelse( $x % 2, $x, $x * 2 ); # [1 4 3 8]
say ifelse( $x % 2, 5, sequence( 3 ) ); # [5 1 5 0]
say ifelse( 42, $x, $x * 2 ); # [1]
In PDL, the general solution to that sort of thing likely involves slicing and similar. Looking at the latest release notes of PDL (2.077), which has a new where_both, I remembered this question (disclosure: I'm current maintainer). While your specific problem only involves a change to the values of even numbers, I'll also show the case of adding 2 to odds:
my ($odd, $even) = where_both($x, $x % 2);
$odd += 2, $even *= 2; # the "," form is just a flourish, it could be 2 lines
It's efficient, in proper PDL style, because the scan of $x only happens once (you won't be surprised to learn it also uses which_both under the hood), and the mutations only look at the slices of the bits that are relevant. This is very similar to your code, but it got captured into a small, widely-reusable function. (I wrote it to turn the TriD EuclidAxes stuff from using Perl for-loops to actually using ndarrays, if you're interested)
Better than $x ? $y : $z? Not to my mind, but it's a matter of style and taste
sub ifelse {
my ($x,$y,$z) = #_;
$x ? $y : $z ;
if($x){$y}else{$z} ;
[$y,$z]->[!$x] ;
[$z,$y]->[!!$x] ;
($x && $y) || $z ; # valid only if $y is always true
(!$x && $z) || $y ; # valid only if $z is always true
}

find frequency of substring in a set of strings

I have as input a gene list where each genes has a header like >SomeText.
For each gene I would like to find the frequency of the string GTG. (number of occurences divided by length of gene). The string should only be counted if it starts at position 1,4,7,10 etc (every thids position).
>ENST00000619537.4 cds:known chromosome:GRCh38:21:6560714:6564489:1 gene:ENSG00000276076.4 gene_biotype:protein_coding transcript_biotype:protein_coding gene_symbol:CH507-152C13.3 description:alpha-crystallin A chain [Source:RefSeq peptide;Acc:NP_001300979]
ATGGATGTGACCATCCAGCACCCCTGGTTCAAGCGCACCCTGGGGCCCTTCTACCCCAGC
CGGCTGTTCGACCAGTTTTTCGGCGAGGGCCTTTTTGAGTATGACCTGCTGCCCTTCCTG
TCGTCCACCATCAGCCCCTACTACCGCCAGTCCCTCTTCCGCACCGTGCTGGACTCCGGC
ATCTCTGAGGTTCGATCCGACCGGGACAAGTTCGTCATCTTCCTCGATGTGAAGCACTTC
TCCCCGGAGGACCTCACCGTGAAGGTGCAGGACGACTTTGTGGAGATCCACGGAAAGCAC
AACGAGCGCCAGGACGACCACGGCTACATTTCCCGTGAGTTCCACCGCCGCTACCGCCTG
CCGTCCAACGTGGACCAGTCGGCCCTCTCTTGCTCCCTGTCTGCCGATGGCATGCTGACC
TTCTGTGGCCCCAAGATCCAGACTGGCCTGGATGCCACCCACGCCGAGCGAGCCATCCCC
GTGTCGCGGGAGGAGAAGCCCACCTCGGCTCCCTCGTCCTAA
>ENST00000624019.3 cds:known chromosome:GRCh38:21:6561284:6563978:1 gene:ENSG00000276076.4 gene_biotype:protein_coding transcript_biotype:protein_coding gene_symbol:CH507-152C13.3 description:alpha-crystallin A chain [Source:RefSeq peptide;Acc:NP_001300979]
ATGGACGCCCCCCCCCCCCACCCAACCACAGGCCTCCTCTCTGAGCCACGGGTTCGATCC
GACCGGGACAAGTTCGTCATCTTCCTCGATGTGAAGCACTTCTCCCCGGAGGACCTCACC
GTGAAGGTGCAGGACGACTTTGTGGAGATCCACGGAAAGCACAACGAGCGCCAGGACGAC
CACGGCTACATTTCCCGTGAGTTCCACCGCCGCTACCGCCTGCCGTCCAACGTGGACCAG
TCGGCCCTCTCTTGCTCCCTGTCTGCCGATGGCATGCTGACCTTCTGTGGCCCCAAGATC
CAGACTGGCCTGGATGCCACCCACGCCGAGCGAGCCATCCCCGTGTCGCGGGAGGAGAAG
CCCACCTCGGCTCCCTCGTCCTAA
>ENST00000624932.1 cds:known chromosome:GRCh38:21:6561954:6564203:1 gene:ENSG00000276076.4 gene_biotype:protein_coding transcript_biotype:protein_coding gene_symbol:CH507-152C13.3 description:alpha-crystallin A chain [Source:RefSeq peptide;Acc:NP_001300979]
ATGCCTGTCTGTCCAGGAGACAGTCACAGGCCCCCGAAAGCTCTGCCCCACTTGGTGTGT
GGGAGAAGAGGCCGGCAGGTTCGATCCGACCGGGACAAGTTCGTCATCTTCCTCGATGTG
AAGCACTTCTCCCCGGAGGACCTCACCGTGAAGGTGCAGGACGACTTTGTGGAGATCCAC
GGAAAGCACAACGAGCGCCAGGACGACCACGGCTACATTTCCCGTGAGTTCCACCGCCGC
TACCGCCTGCCGTCCAACGTGGACCAGTCGGCCCTCTCTTGCTCCCTGTCTGCCGATGGC
ATGCTGACCTTCTGTGGCCCCAAGATCCAGACTGGCCTGGATGCCACCCACGCCGAGCGA
GCCATCCCCGTGTCGCGGGAGGAGAAGCCCACCTCGGCTCCCTCGTCCTAA
Output:
Gene Frequency
Gene1: 3
Gene2 6.3
....
I was thinging of something like this, but I dont now how to define the positions requirements:
freq <- sapply(gregexpr("GTG",x),function(x)if(x[[1]]!=-1) length(x) else 0)
Here is an idea in R using stringi.
We use stri_locate_all_fixed() to find the start and end position of each GTG occurence. Then we create a column condition to test if start position is in 1,4,7,10,13,16,19,22 ....
library(stringi)
library(dplyr)
data.frame(stri_locate_all_fixed(gene1, "GTG")) %>%
mutate(condition = start %in% seq(1, nchar(gene), 3))
Which gives:
# start end condition
#1 4 6 TRUE
If you want to generalize this to a list of genes, you could do:
lst <- list(gene1, gene2, gene3)
res <- lapply(lst, function(x) {
data.frame(stri_locate_all_fixed(x, "GTG")) %>%
mutate(condition = start %in% seq(1, nchar(x), 3))
})
Which would give:
#[[1]]
# start end condition
#1 4 6 TRUE
#
#[[2]]
# start end condition
#1 NA NA FALSE
#
#[[3]]
# start end condition
#1 3 5 FALSE
#2 9 11 FALSE
#3 21 23 FALSE
#4 70 72 TRUE
#5 75 77 FALSE
Following #Sobrique's comment, if divided by length means number of occurences respecting condition divided by total number of char in each gene, you could do:
lapply(1:length(res), function(x) sum(res[[x]][["condition"]]) / nchar(lst[[x]]))
Which would give:
#[[1]]
#[1] 0.004830918
#
#[[2]]
#[1] 0
#
#[[3]]
#[1] 0.003021148
Here's a Perl solution that does as you ask
But I don't understand how your example output is derived: the first and last sequences have only one occurrence of GTG in the positions you require, and the second sequence has none at all. That means the outputs are 1 / 207, 0 / 74, and 1 / 331 respectively. None of those are anything like 3 and 6.3 that you say you're expecting
This program expects the path to the input file as a parameter on the command line
use strict;
use warnings 'all';
print "Gene Frequency\n";
my $name;
local $/ = '>';
while ( <> ) {
chomp;
next unless /\S/;
my ($name, $seq) = split /\n/, $_, 2;
$seq =~ tr/A-Z//cd;
my $n = 0;
while ( $seq =~ /(?=GTG)/g ) {
++$n if $-[0] % 3 == 0;
}
printf "%-7s%.6f\n", $name, $n / length($seq);
}
output
Gene Frequency
Gene1 0.004831
Gene2 0.000000
Gene3 0.003021
Here is an alternate solution that does not use a pattern match. Not that it will matter much.
use strict;
use warnings;
my $gene;
while ( my $line = <> ) {
if ( $line =~ /^>(.+)/ ) {
$gene = $1;
next;
}
chomp $line;
printf "%s: %s\n",
$gene,
( grep { $_ eq 'GTG' } split /(...)/, $line ) / length $line;
}
Output:
Gene1: 0.00483091787439614
Gene2: 0
Gene3: 0.00302114803625378
It is essentially similar to Sobrique's answer, but assumes that the gene lines contain the right characters. It splits up the gene string into a list of three-character pieces and takes the ones that are literally GTG.
The splitting works by abusing the fact that split uses a pattern as the delimiter, and that it will also capture the delimiter if a capture group is used. Here's an example.
my #foo = split /(...)/, '1234567890';
p #foo; # from Data::Printer
__END__
[
[0] "",
[1] 123,
[2] "",
[3] 456,
[4] "",
[5] 789,
[6] 0
]
The empty elements get filter out by grep. It might not be the most efficient way, but it gets the job done.
You can run it by calling perl foo.pl horribly-large-gene-sequence.file.
Well, you have an R solution. I've hacked something together in perl because you tagged it:
#!/usr/bin/env perl
use strict;
use warnings;
my $target = 'GTG';
local $/ = "\n>";
while ( <> ) {
my ($gene) = m/(Gene\d+)/;
my #hits = grep { /^$target$/ } m/ ( [GTCA]{3} ) /xg;
print "$gene: ".( scalar #hits), "\n";
}
This doesn't give the same results as your input though:
Gene1: 1
Gene2: 0
Gene3: 1
I'm decomposing your string into 3 element lists, and looking for ones that specifically match. (And I haven't divided by length, as I'm not entirely clear if that's the actual string length in letters, or some other metric).
Including length matching - we need to capture both name and string:
#!/usr/bin/env perl
use strict;
use warnings;
local $/ = "\n>";
while (<>) {
my ($gene, $gene_str) = m/(Gene\d+)\n([GTCA]+)/m;
my #hits = grep { /^GTG$/ } $gene_str =~ m/ ( [GTCA]{3} ) /xg;
print "$gene: " . #hits . "/". length ( $gene_str ), " = ", #hits / length($gene_str), "\n";
}
We use <> which is the 'magic' filehandle, and tells perl to read from either STDIN or a file specified on command line. Much like sed or grep does.
With your input:
Gene1: 1/207 = 0.00483091787439614
Gene2: 0/74 = 0
Gene3: 1/331 = 0.00302114803625378
Here is a function I created based on your requirement. I am pretty sure there are alternate ways better than this but this solves the problem.
require(stringi)
input_gene_list<- list(gene1= "GTGGGGGTTTGTGGGGGTG", gene2= "GTGGGGGTTTGTGGGGGTG", gene3= "GTGGGGGTTTGTGGGGGTG")
gene_counter<- function(gene){
x<- gene
y<- gsub(pattern = "GTG",replacement = "GTG ", x = x, perl=TRUE)
if(str_count(y,pattern = "GTG")) {
gene_count<- unlist(gregexpr(pattern = " ", y))
counter<- 0
for(i in 1:length(gene_count)){
if((gene_count[i] %% 3) == 1) counter=counter+1
}
return(counter/nchar(x))
}
}
output_list<- lapply(input_gene_list, function(x) gene_counter(x))
result<- t(as.data.frame(output_list))
result
[,1]
gene1 0.1052632
gene2 0.1052632
gene3 0.1052632
Also share your thoughts on it! Thanks!

How can I clean up this code to be shorter? [duplicate]

This question already has answers here:
Incremental variable definition
(2 answers)
Closed 4 years ago.
I'm using AutoIt:
$1 = GetItemBySlot(1, 1)
$2 = GetItemBySlot(1, 2)
$3 = GetItemBySlot(1, 3)
$4 = GetItemBySlot(1, 4)
$5 = GetItemBySlot(1, 5)
The code repeats for 40 lines. How can I shorten it?
You could shorten this by using Assign() and
Eval().
For $i = 1 To 5
Assign($i, GetItemBySlot(1, $i))
Next
That would be 3 lines instead of n lines. During runtime this will be expanded to:
Assign(1, GetItemBySlot(1, 1))
Assign(2, GetItemBySlot(1, 2))
Assign(3, GetItemBySlot(1, 3))
Assign(4, GetItemBySlot(1, 4))
Assign(5, GetItemBySlot(1, 5))
To get the data of those variables you need to use the Eval function. So
For $i = 1 To 5
Eval($i)
Next
returns the value of GetItemBySlot(1, $i).
For $i = 1 To 40
$aItemsBySlot[$i] = GetItemBySlot(1, $i)
Next
As per Documentation - Intro - Arrays:
An Array is a variable containing a series of data elements. Each element in this variable can be accessed by an index number which relates to the position of the element within the Array - in AutoIt the first element of an Array is always element [0]. Arrays elements are stored in a defined order and can be sorted.
Example in GetItemBySlotMulti() (untestes, no error-checking):
Global $aItems
; Assign:
$aItems = GetItemBySlotMulti(1, 40)
; Retrieve single value (output item #1 to console):
ConsoleWrite($aItems[1] & #CRLF)
; Retrieve all values:
For $i = 1 To $aItems[0]
ConsoleWrite($aItems[$i] & #CRLF)
Next
; Retrieve amount of items:
ConsoleWrite($aItems[0] & #CRLF)
; Re-assign a single value (re-assign item #1):
$aItems[1] = GetItemBySlot(1, 1)
; Function (used to assign example):
Func GetItemBySlotMulti(Const $iSlot, Const $iItems)
Local $aItemsBySlot[$iItems +1]
$aItemsBySlot[0] = $iItems
For $i = 1 To $iItems
$aItemsBySlot[$i] = GetItemBySlot($iSlot, $i)
Next
Return $aItemsBySlot
EndFunc
Related.

XQuery difference between same function different implementation

Return the number of cycles:
let $bd := doc("document")
return count ( for $c in $bd//cycle
where $c[#id]
return $c
)
Every cycle has an ID, not important here but it is a must to specify it.
What is the difference between the above use of count and the below use of count?
let $bd := doc("document")
let $c := $bd//cycle[#id]
return count($c)
I dont know the difference between these 2 XQueries return same result but following the same pattern the next 2 queries should work but the 2nd one doesnt... Here they are:
The total of hours of modules which is above 100.
*Working query*
let $bd:=doc("document")
return sum (
for $m in $bd//module[#id]
where $m/hours>100
return $m/hours
)
*Not working query*
let $bd := doc("document")
for $c in $bd//module[#id]
where $c/hours>100
return sum($c/hours)
Id like to know why following the same "pattern" the second query is not working.
The output of the not working query is this one:
160 160 256 224 192 160
Its not the result i need, I want the sum of all them.
The first two expressions are functionally equivalent. The difference is the use of FLWOR vs. XPath to select your sequence.
In the second example, you are calling sum() on each item of the sequence ($c/hours), instead of on the sequence itself:
let $bd := doc("document")
return sum(
for $c in $bd//module[#id]
where $c/hours>100
return $c/hours)
You could also use XPath:
let $bd := doc("document")
let $c := $bd//module[#id][hours>100]
return sum($c/hours)
Or similarly assign the result of the FLWOR to a variable and sum that:
let $bd := doc("document")
let $c :=
for $m in $bd//module[#id]
where $m/hours>100
return $m/hours
return sum($c)

Resources