所有k-mers / n-gram


21

介绍

我们有直方图计数,但没有列出全部。

每年,Dyalog有限公司都会举办一次学生比赛。面临的挑战是编写好的 APL代码。这是今年第六个问题的与语言无关版本。

我得到比赛原作者的明确许可,可以在此处发布此挑战。跟随提供的链接并与作者联系,以进行验证。

问题

术语k-mer通常是指字符串中包含的所有可能的长度为k的子字符串。在计算基因组学中,k-mer指通过DNA测序获得的读数中所有可能的子序列(长度为k)。编写一个函数/程序,该函数需要一个字符串和一个k(子字符串长度),并返回/输出原始字符串的k-mers的向量。

例子

[4,"ATCGAAGGTCGT"]["ATCG","TCGA","CGAA","GAAG","AAGG","AGGT","GGTC","GTCG","TCGT"]

k >字符串长度?不返回任何结果/任何空结果:
[4,"AC"][]""[""]


4
输出顺序重要吗?当子字符串多次出现时,是否应该在输出中重复它?
feersum'1

1
我可以返回用换行符分隔的必需子字符串的字符串,而不是像这样的字符串数组吗?
Leaky Nun

我们是否也可以将字符串作为字符数组输入和输出(例如['A', 'T', 'C', 'G']代替"ATCG"
Adnan,

此PPCG挑战中是否允许Dyalog APL答案(因为该挑战也由Dyalog主持)?
Kritixi Lithos'5

1
@feersum顺序很重要,应该重复。这就像一个滑动窗口。
阿达姆(Adám)'17年

Answers:



8

八度,28字节

@(N,s)s((1:N)+(0:nnz(s)-N)')

在线尝试!

对于k>,字符串长度在Octave 4.2.1-windows中有效,但在tio(Octave 4.0.3)中无效。

创建连续元素的数字索引,并以此索引字符串。

s= "ATCGAAGGTCGT"
N = 4
idx = (1:N)+(0:nnz(s)-N)'
 =
    1    2    3    4
    2    3    4    5
    3    4    5    6
    4    5    6    7
    5    6    7    8
    6    7    8    9
    7    8    9   10
    8    9   10   11
    9   10   11   12

s(idx) =

ATCG
TCGA
CGAA
GAAG
AAGG
AGGT
GGTC
GTCG
TCGT



5

Brachylog,3个字节

s₎ᶠ

在线尝试!

眼镜:

  • 输入: ["ATCGAAGGTCGT",4]
  • 参数: Z
  • 输出: Z = ["ATCG","TCGA","CGAA","GAAG","AAGG","AGGT","GGTC","GTCG","TCGT"]

怎么运行的

s₎ᶠ
s    Output is a substring of first element of input,
 ₎   with length specified by second element of input.
  ᶠ  Find all solutions.

5

Python 3中 47个45 42字节

多亏了ovs -3个字节(使用Python 3的解压缩以a[n-1:]在尾部重用。)

f=lambda a,n:a[n-1:]and[a[:n],*f(a[1:],n)]

一个递归函数,它接收字符串,a切片长度n,并返回切片列表或空字符串。

a[n-1:]从第n-1 (索引为0的元素)开始获取当前字符串的一部分,以测试是否剩余足够的元素(在Python中,空字符串为false)-这比等效字符串短len(a)>=n

  • 如果有足够的元素,则构造一个列表[...],其中包含n字符串的第一个元素a[:n],以及再次调用该函数的解压缩结果,以及*f(...)当前输入的出队版本(不包含第一个元素)a[1:]

  • 如果没有足够的元素,则在a[n-1:]返回时到达递归的尾部(在这种情况下为空字符串)。

在线尝试!


45(对于Python 2或3),具有:

f=lambda a,n:a[n-1:]and[a[:n]]+f(a[1:],n)or[]

f=lambda a,n:a[n-1:]and[a[:n],*f(a[1:],n)]for 42 bytes(Python 3)TIO
ovs '17

@ovs,非常好,我问这是否可以接受(因为它们的空结果是一个字符串,而非空结果是一个列表)。
乔纳森·艾伦

4

J,2个字节

,\

它不是完整的程序,而是具有操作员的功能。

这样称呼它:

echo 4 ,\ 'ATCGAAGGTCGT'

在线尝试!

怎么运行的

运算符(称为“连接词”)\(名为“中 ”)的用法如下:

(x u\ y)将动词应用于u列表的连续部分y(称为中缀)。

u这种情况下的功能(称为“动词”),是一个简单的“ 附加 ”功能:

创建一个数组,其中包含的项,x后跟的项y


3

Mathematica,21个字节

##~StringPartition~1&

匿名函数。以一个字符串和一个数字(按此顺序)作为输入,并返回一个字符串列表作为输出。


3

R,65 61字节

-2个字节,感谢MickyT

-2个字节,通过更改索引

返回一个匿名函数。

function(s,n,x=nchar(s))`if`(n>x,'',substring(s,x:n-n+1,n:x))

substring循环浏览索引(substr与之1相反),如果起始索引小于1,则默认为,因此它检查并返回空字符串。

x:n-n+1等价于,1:(x-n+1)因为:优先于和/差

在线尝试!


您可以使用function(s,n,x=nchar(s))if 来节省几个字节(n>x,'',substring(s,1:(x-n+1),n:x))
MickyT's

@MickyT,谢谢!我还注意到我可以通过更改索引计算来删除一些字节
朱塞佩(Giuseppe)


2

水母,7个字节

p
_I
\i

在线尝试!

怎么运行的

在linear:中p(\(I,i)),哪里p是print并\获取所需的子字符串。

I是原始的第一输入,i而是评估的第二输入。

在水母中,每个函数和运算符都有两个自变量,一个自右,一个自底。在这里,该函数p从的输出获取参数_,这是我们要使用运算符\获取子字符串所必需的。




2

Clojure,19个字节

好吧,很方便:

#(partition % 1 %2)

例子:

(def f #(partition % 1 %2))
(println [(f 4 "ATCGAAGGTCGT")
          (f 4 "abc")])

[((A T C G) (T C G A) (C G A A) (G A A G) (A A G G) (A G G T) (G G T C) (G T C G) (T C G T))
 ()]

2

CJam,4个字节

{ew}

希望在堆栈上保留参数的匿名块,之后将结果留在堆栈上。

在线尝试!

ew 是内置的,可以完全满足要求。


5
:我只有一两件事要说EW
亚当

2

视网膜41 38字节

.*$
$*
!&`(.)+(?=.*¶(?<-1>.)+(?(1)¶)$)

在线尝试!

取字符串并在单独的行上计数。前两行用于计数从十进制转换为一元,因此,如果一元输入是可以接受的,则字节数将减少到34 31。编辑:保存3字节由于@FryAmTheEggman。或者,如果您愿意,可以使用48字节的版本来处理字符串中的换行符,尽管这会产生令人困惑的输出:

.*$
$*
!&`(\S|\s)+(?=[\S\s]*¶(?<-1>.)+(?(1)$.)$)

@KritixiLithos我不明白您的解决方案如何考虑在内……
尼尔(Neil)

哦,对不起,我只好放屁了[_ <
Kritixi Lithos

如果字符串可以包含换行符,则不一定有效,因此我认为您可以更改(?!)
FryAmTheEggman '17

2

带图像包的八度,29字节

@(s,n)[im2col(+s, [1 n])' '']

在线尝试!

说明

该函数im2col(m,b)采用矩阵mb从矩阵中提取大小的块,并将其排列为列。默认情况下,块是滑动的(与众不同)。在这里,矩阵m是输入字符串的ASCII码的行向量s(这是通过来完成的+s,它比standard短double(s)),其大小b[1 n]为了获得n元素的水平滑动块。

将结果转置(使用'比transpose短的complex-conjugate transpose .')将列转换为行,然后将其转换回char([... '']比标准短char(...))。



1

Python 3,49个字节

f=lambda a,n:[a[i:i+n]for i in range(len(a)-n+1)]

在线尝试!

一种非递归的解决方案,尽管不短。

与Python 2兼容。


您可以drop f=,节省两个字节,因为您没有f在其他任何地方使用。默认情况下,仅声明未使用的函数可以不命名。
Xcoder先生17年

1

PHP,75字节

在线版本

for([,$n,$s]=$argv;$i+$n-1<strlen($s);)$r[]=substr($s,$i++,$n);print_r($r);

80个字节,没有双精度值

for([,$n,$s]=$argv;$i+$n-1<strlen($s);)$r[$p=substr($s,$i++,$n)]=$p;print_r($r);

1

Haskell,39个字节

n#s|length s<n=[]|1<2=take n s:n#tail s

用法示例:4 # "ABCDEF"-> ["ABCD","BCDE","CDEF"]在线尝试!

一个简单的递归,只要n输入字符串的长度不小于,就可以保持输入字符串的前一个字符和字符串的尾部n


1

Microsoft Sql Server,199字节

create function dbo.f(@s nvarchar(max),@ int)returns table as return
with v as(select 2 p,left(@s,@)g where len(@s)>=@ union all
select p+1,substring(@s,p,@)from v where len(@s)>p-2+@)select g from v

检查。



1

堆叠,7个字节

infixes

在线尝试!

很标准。没有此内置函数,它将变为20个字节:

{%x#'y-#+:>y#-#>x\#}

这是:

{%x#'y-#+:>y#-#>x\#}
{%                 }   dyad; first arg: x, second arg: y
  x#'                  length of x (the array)
     y-                minus y (the skew)
       #+              plus 1
         :>            range [x, y]
           y#-         y minus 1
              #>       range from [[x, y], [x, y] + y]
                x\#    get indices from x


1

C#89字节

void a(string s,int n){for(int i=n;i<=s.Length;)Console.WriteLine(s.Substring(i++-n,n));}

在线尝试!

我在C#中可以找到的最佳方法与Java基本相同


1

Ruby,48个 46字节

->(s,k){0.upto(s.size-k).map{|i|s[i..i+k-1]}}

没有特别的技巧,只是一个stabby-lambda定义了一个函数,该函数从每个有效的起始点提取所需的子字符串。

保存了两个字节,因为似乎不需要存储lambda。


1

V,16字节

òÀ|ly0Ïp
"_xòkVp

恐怕打的不是很好,打了“如果k> len(str)删除线”。输入在文件中,k是参数。解释前打高尔夫球

在线尝试!


如果您不尝试处理k> len(str)情况会怎样?
2015年

根据我使用的方法(尤其是在此方法中),它只是将字符串
保留

1

标准ML(mosml),109 65 61字节

fun f(n,x)=if n>length(x)then[]else List.take(x,n)::f(n,tl x)

接受一个数字和一个字符列表(在SML世界中,这是字符串的常见替代品)。(确实适用于所有列表。)

用法:

- f(3,explode("ABCDEFGH"));
> val it =
    [[#"A", #"B", #"C"], [#"B", #"C", #"D"], [#"C", #"D", #"E"],
     [#"D", #"E", #"F"], [#"E", #"F", #"G"], [#"F", #"G", #"H"]] :
  char list list
- f(7, explode("ABCD"));
> val it = [] : char list list

变更日志:

  • 是的,有一个标准库。(-44字节)
  • 按照建议将比较和nil更改为[](-4字节)

1
您可以通过更改if length(x)<n then为保存一个字节if n>length(x)then。但是,由于SML完全有可能处理字符串,因此我不确定是否允许将explode其应用于输入字符串。
Laikoni '17

then nil else可以缩短为then[]else
Laikoni '17

@Laikoni也不确定,不过\\ _(ツ)_ /
¯– L3viathan

使用其他一些库函数,我得到了一个68字节的版本,该版本处理字符串而不是字符列表。您的方法也可以缩短为54个字节:fun f$n=if n>length$then[]else List.take($,n)::f(tl$)n
Laikoni '17

1

JavaScript(Firefox 30-57),51个字节

(s,n,t='')=>[for(c of s)if((t+=c)[n-1])t.slice(-n)]

ES6中的64个字节:

(s,n,t=s.slice(0,--n))=>[...s.slice(n)].map(c=>(t+=c).slice(~n))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.