ワトソン・クリック回文


31

問題

任意のDNAストリングがWatson-Crick回文であるかどうかを判別できる関数を作成します。この関数はDNAストリングを受け取り、ストリングがWatson-Crick回文である場合はtrue値を、そうでない場合はfalse値を出力します。(TrueおよびFalseは、それぞれ1および0として表すこともできます。)

DNAストリングは、好みに応じてすべて大文字でもすべて小文字でもかまいません。

また、DNAストリングは空になりません。

説明

DNAストリングは、その逆の補数がそれ自体に等しい場合、ワトソンクリック回文です。

DNA文字列が与えられた場合、最初にそれを反転し、次にDNA塩基(A↔TおよびC↔G)に従って各文字を補完します。元の文字列が逆相補文字列と等しい場合、それはワトソンクリック回文です。

詳細については、この質問を参照してください。DNA文字列の中で最も長い部分文字列を見つける必要がある場合、その部分文字列はワトソンクリック回文であるという別の課題です。

ゴール

これはコードゴルフであり、最短のコードが勝ちます。

テストケース

形式は<input> = <output>です。

ATCGCGAT = true
AGT = false
GTGACGTCAC = true
GCAGTGA = false
GCGC = true
AACTGCGTTTAC = false
ACTG = false


3
誰かは、ワトソンクリック回文でもあるDNA#でプログラムを書く必要があります。:D(不可能な場合があります)
-mbomb007

または、必要に応じて、「2つのジェネレーターのフリーグループに次数2がある場合、単語はワトソン-クリックパリンドロームです」(またはnジェネレーター!)。
wchargin

(技術的には「最大で2個」だと思います)
-wchargin

1
@AndrasDeakワトソンズの本によると、フランクリンは明らかに彼らの味方でした。彼女はそれを信じることを拒否したため、らせんを示すX線の引き渡しを繰り返し拒否しました(私が覚えているように)。いずれにせよ発見に興味があるなら、読む価値があります。
黒曜石のフェニックス

回答:


27

05AB1E10 7バイト

コード:

Â'š×‡Q

説明:

文字列が回文であるかどうかを確認するには、入力と入力を確認し、atスワップとcgスワップを行ってから、逆にするだけです。それが私たちがやろうとしていることです。入力をプッシュし、Â(bifurcate)を使用して入力を逆にします。さて、トリッキーな部分があります。'š×はの圧縮バージョンですcreating。逆にすると、コード内にその理由が表示されます。

CreATinG
|  ||  |
GniTAerC

これは、逆入力を音訳するために使用されます。文字変換はで行われます。その後、入力と音訳された入力が有効かどうかを確認し、Qその値を出力します。これが、スタックが入力に対してどのように見えるかですactg

          # ["actg", "gtca"]
 'š×       # ["actg", "gtca", "creating"]
    Â      # ["actg", "gtca", "creating", "gnitaerc"]
     ‡     # ["actg", "cagt"]
      Q    # [0]

これは、デバッグフラグ(ここで試してみてください)でも確認できます。

CP-1252エンコードを使用します。オンラインでお試しください!


4
非常に、えー、創造的 ...
トビースパイト

2
この言語にはいくつかの非常にきちんとした機能があります
マイル

18

ゼリー、9 バイト

O%8µ+U5ḍP

オンラインでお試しください!または、すべてのテストケースを確認します

使い方

O%8µ+U5ḍP  Main link. Argument: S (string)

O          Compute the code points of all characters.
 %8        Compute the residues of division by 8.
           This maps 'ACGT' to [1, 3, 7, 4].
   µ       Begin a new, monadic link. Argument: A (array of residues)
    +U     Add A and A reversed.
      5ḍ   Test the sums for divisibility by 5.
           Of the sums of all pairs of integers in [1, 3, 7, 4], only 1 + 4 = 5
           and 3 + 7 = 10 are divisible by 5, thus identifying the proper pairings.
        P  Take the product of the resulting Booleans.

4
Pythonはこの答えとかなり競合していると思います!私の答えの最初の9バイトを比較してください:lambda s:。それがほぼ完全なソリューションです!
-orlp

ちょっと待って、「どのように機能するか」の部分では実際にどのように機能するかを説明していません...なぜ8の剰余と5の和ですか?? 文字はどこで補完されますか?
ゼロワン

@ZeroOneその部分を明確にしました。
デニス

ああすごい!それは非常に賢いです。:)ありがとう!
ゼロワン


8

Perl、27バイト

+2を含む -lp

STDINに入力し、1を出力するか、何も出力しません。

dnapalin.pl <<< ATCGCGAT

dnapalin.pl

#!/usr/bin/perl -lp
$_=y/ATCG/TAGC/r=~reverse

交換する$_=ことにより、$_+=取得するために0偽の場合の代わりの空



7

網膜34 33バイト

$
;$_
T`ACGT`Ro`;.+
+`(.);\1
;
^;

オンラインでお試しください!(すべてのテストケースを一度に実行するために少し変更されています。)

説明

$
;$_

入力を複製するには、文字列の最後に一致するものを挿入し、;その後に入力全体を挿入します。

T`ACGT`Ro`;.+

入力の後半のみを一致さ;.+せ、音訳でペアの置換を実行します。ターゲット・セットについてRoo言及他のセット、さoに置き換えていますACGT。ただしR、このセットを逆にすると、2つのセットは実際には次のようになります。

ACGT
TGCA

入力がDNAパリンドロームである場合、入力の後にその逆が続きます(で区切られます;)。

+`(.);\1
;

繰り返し(+;。これは、のみ;が残るか、周囲の2つの文字;が同一でなくなるまで続きます。つまり、文字列が互いに逆ではないことを意味します。

^;

最初の文字が;and printであるかどうか、0または1それに応じてチェックします。


6

JavaScript(ES6)、59バイト

f=s=>!s||/^(A.*T|C.*G|G.*C|T.*A)$/.test(s)&f(s.slice(1,-1))

Regexpを使用せずにできることは62バイトでした。

f=s=>!s||parseInt(s[0]+s.slice(-1),33)%32%7<1&f(s.slice(1,-1))

5

ルビー、35

私は他の方法を試しましたが、明らかな方法は最短でした:

->s{s.tr('ACGT','TGCA').reverse==s}

テストプログラムで

f=->s{s.tr('ACGT','TGCA').reverse==s}

puts f['ATCGCGAT']
puts f['AGT']
puts f['GTGACGTCAC']
puts f['GCAGTGA']
puts f['GCGC']
puts f['AACTGCGTTTAC'] 

2
->s{s.==s.reverse.tr'ACGT','TGCA'}バイトが短い
ミッチシュワルツ

@MitchSchwartzうわー、それは動作しますが、それが最初に何の.ためにあるのか分かりません。コードそれなしで私により適切に見えますが、それを実行させるために必要です。どこに文書化されていますか?
レベルリバーセント

自分でそれを理解したくないのですか?
ミッチシュワルツ

@MitchSchwartzハハハ、私はすでに試しました。空白に関するルビーの要件は非常に特異だと思います。期間の奇妙な要件は、まったく別の問題です。私にはいくつかの理論がありますが、それらはすべて間違っているかもしれません。==演算子ではなくメソッドとして扱うことに関係があるのではないかと思いますが、記号による検索は不可能です。
レベルリバーセント

あなたは正しく疑った。:)それはただの古いメソッド呼び出しです。
ミッチシュワルツ

5

Haskell、48 45バイト

(==)=<<reverse.map((cycle"TCG_A"!!).fromEnum)

使用例:(==)=<<reverse.map((cycle"_T_GA__C"!!).fromEnum) $ "ATCGCGAT"-> True

非ポイントフリーバージョンは

f x = reverse (map h x) == x           -- map h to x, reverse and compare to x
h c = cycle "TCG_A" !! fromEnum c      -- take the ascii-value of c and take the
                                       -- char at this position of string
                                       -- "TCG_ATCG_ATCG_ATCG_A..."

編集:@Mathias Dolidonは3バイトを節約しました。ありがとう!


cycle "TCG_A" でも動作します。:)
マティアスドリドン16


4

ジュリア、47 38バイト

s->((x=map(Int,s)%8)+reverse(x))%50

これは、Char配列を受け入れてブール値を返す匿名関数です。呼び出すには、変数に割り当てます。

これは、単純なソリューションよりも短いDennisのアルゴリズムを使用しています。我々は8によって分割された各コードポイントの残りの部分を取得し、それ自体に5で除算から余りを得る、反転、及び全ての最後のステップを使用して達成される0であるか否かを確認すること追加のインフィックスバージョンissubsetの両方の引数をキャストし、Setチェックする前に。この手段[0,0,0]のサブセットを宣言されて0いるので、Set([0,0,0]) == Set(0)。これは、0に対する明示的なチェックよりも短いです。

オンラインでお試しください!

デニスのおかげで9バイト節約できました!





3

Oracle SQL 11.2、68バイト

SELECT DECODE(TRANSLATE(REVERSE(:1),'ATCG','TAGC'),:1,1,0)FROM DUAL; 

2
このようなSQLを使用すると、以前に私のプロジェクトのいくつかのレポートを作成しておく必要があると確信しています
...-corsiKa

3

ジュリア0.4、22バイト

s->s$reverse(s)⊆""

文字列には、制御文字EOT(4)およびNAK(21)が含まれています。入力は文字配列の形式でなければなりません。

この方法では、入力の文字と反転入力の対応する文字のXORを取ります。有効なペアリングの場合、これは文字EOTまたはNAKになります。これらの文字の文字列に含めるかどうかをテストすると、目的のブール値が生成されます。

オンラインでお試しください!


3

C、71

r,e;f(char*s){for(r=0,e=strlen(s)+1;*s;s++)r|=*s*s[e-=2]%5^2;return!r;}

デニスが保存した2バイト。定数:追加の2つのバイトは、小文字入力のために適合させることによって保存された3721に改訂されている52

C、75

i,j;f(char*s){for(i=j=0;s[i];i++)j|=s[i]*s[strlen(s)-i-1]%37!=21;return!j;}

1バイトの保存:2つのASCIIコードmod 37の積を取ることで括弧を削除しました。有効なペアは21と評価されます。大文字入力を想定しています。

C、76

i,j;f(char*s){for(i=j=0;s[i];i++)j|=(s[i]+s[strlen(s)-i-1])%11!=6;return!j;}

有効なペアのASCIIコードの合計が138または149であるという事実を使用します。mod11を使用した場合、これらは合計が6になる唯一のペアです。大文字の入力を想定しています。

テストプログラムに参加していない

i,j;

f(char *s){
   for(i=j=0;s[i];i++)                  //initialize i and j to 0; iterate i through the string
     j|=(s[i]+s[strlen(s)-i-1])%11!=6;  //add characters at i from each end of string, take result mod 11. If not 6, set j to 1
return!j;}                              //return not j (true if mismatch NOT detected.)

main(){
  printf("%d\n", f("ATCGCGAT"));
  printf("%d\n", f("AGT"));
  printf("%d\n", f("GTGACGTCAC"));
  printf("%d\n", f("GCAGTGA"));
  printf("%d\n", f("GCGC"));
  printf("%d\n", f("AACTGCGTTTAC"));
} 

1
r,e;f(char*s){for(r=0,e=strlen(s)+1;*s;s++)r|=*s*s[e-=2]%37^21;return!r;}数バイト節約します。
デニス

@Dennisに感謝します、私は本当にポインターを変更する気分ではありませんでしたが、それはバイトを絞り出しました!私が見てきたはずです!=> ^自分自身を。入力を小文字に変更して、さらに2を減らしました。両方のマジックナンバーが1桁になりました。
レベルリバーセント

3

ファクター、72バイト

残念ながら、正規表現はここで私を助けることはできません。

[ dup reverse [ { { 67 71 } { 65 84 } { 71 67 } { 84 65 } } at ] map = ]

逆引き、ルックアップテーブル、等しい比較。


うわー、それはたくさんの空白です!!! それはすべて必要ですか?また、言語のホームページへのリンクが役立つでしょう。
レベルリバーセント

@LevelRiverSt残念ながら、そのすべてが必要です。ヘッダーにリンクを追加します。

3

Bash + coreutils、43 32バイト

[ `tr ATCG TAGC<<<$1|rev` = $1 ]

テスト:

for i in ATCGCGAT AGT GTGACGTCAC GCAGTGA GCGC AACTGCGTTTAC; do ./78410.sh $i && echo $i = true || echo $i = false; done
ATCGCGAT = true
AGT = false
GTGACGTCAC = true
GCAGTGA = false
GCGC = true
AACTGCGTTTAC = false

3

J-21バイト

0=[:+/5|[:(+|.)8|3&u:

デニスの方法に基づく

使用法

   f =: 0=[:+/5|[:(+|.)8|3&u:
   f 'ATCGCGAT'
1
   f 'AGT'
0
   f 'GTGACGTCAC'
1
   f 'GCAGTGA'
0
   f 'GCGC'
1
   f 'AACTGCGTTTAC'
0
   f 'ACTG'
0

説明

0=[:+/5|[:(+|.)8|3&u:
                 3&u:    - Convert from char to int
               8|        - Residues from division by 8 for each
            |.           - Reverse the list
           +             - Add from the list and its reverse element-wise
        [:               - Cap, compose function
      5|                 - Residues from division by 5 for each
    +/                   - Fold right using addition to create a sum
  [:                     - Cap, compose function
0=                       - Test the sum for equality to zero

3

ラビリンス、42バイト

_8
,%
;
"}{{+_5
"=    %_!
 = """{
 ;"{" )!

ゼロ除算エラー(STDERRのエラーメッセージ)で終了します。

オンラインでお試しください!

レイアウトは非常に非効率的と感じていますが、今ゴルフをする方法が見当たりません。

説明

この解決策は、デニスの算術トリックに基づいています。すべての文字コードを法とし8、両端からペアを追加し、で割り切れるようにし5ます。

ラビリンスプライマー:

  • Labyrinthには、mainaux(iliary)の任意精度整数の2つのスタックがあり、最初は(暗黙の)無限量のゼロで埋められます。
  • ソースコードは迷路に似ており、指示ポインター(IP)が可能な場合(コーナーの周りであっても)通路をたどります。コードは、読み取り順序の最初の有効な文字、つまりこの場合は左上隅から始まります。IPが任意の形式のジャンクション(つまり、元のセルに加えていくつかの隣接セル)に到達すると、メインスタックの最上部に基づいて方向を選択します。基本的なルールは次のとおりです。負の場合は左に曲がり、ゼロの場合は先に進み、正の場合は右に曲がります。そして、壁があるためにこれらのいずれかが不可能な場合、IPは反対方向を取ります。IPは、行き止まりに到達したときにも向きを変えます。
  • 数字は、メインスタックの最上部に10を掛けてから数字を追加することで処理されます。

コードは小さな2x2の時計回りループで始まり、8を法とするすべての入力を読み取ります。

_   Push a 0.
8   Turn into 8.
%   Modulo. The last three commands do nothing on the first iteration
    and will take the last character code modulo 8 on further iterations.
,   Read a character from STDIN or -1 at EOF. At EOF we will leave loop.

;破棄し-1ます。メインスタックの上部(最後の文字)を下に移動する別の時計回りのループに入ります。

"   No-op, does nothing.
}   Move top of the stack over to aux. If it was at the bottom of the stack
    this will expose a zero underneath and we leave the loop.
=   Swap top of main with top of aux. The effect of the last two commands
    together is to move the second-to-top stack element from main to aux.
"   No-op.

短い線形ビットがあります:

{{  Pull two characters from aux to main, i.e. the first and last (remaining)
    characters of the input (mod 8).
+   Add them.
_5  Push 5.
%   Modulo.

これで、IPは分岐点として機能し、分岐として機能して5での可分性をテストします。モジュロの結果がゼロでない場合、入力がWatson-Crick回文ではないことがわかり、東に曲がります。

_   Push 0.
!   Print it. The IP hits a dead end and turns around.
_   Push 0.
%   Try to take modulo, but division by zero fails and the program terminates.

それ以外の場合、入力の残りをチェックし続ける必要があるため、IPは南に進み続けます。{残りの入力の底部上に引っ張ります。入力を使い果たした場合、これは0auxの下部から)となり、IPは南に移動し続けます。

)   Increment 0 to 1.
!   Print it. The IP hits a dead end and turns around.
)   Increment 0 to 1.
{   Pull a zero over from aux, IP keeps moving north.
%   Try to take modulo, but division by zero fails and the program terminates.

それ以外の場合、チェックする文字列にはさらに文字があります。IPは西に曲がり、次の(時計回りの)2x2ループに移動します。これは主にノーオペレーションで構成されています。

"   No-op.
"   No-op.
{   Pull one value over from aux. If it's the bottom of aux, this will be
    zero and the IP will leave the loop eastward.
"   No-op.

このループの後、最初と最後の文字を除き、先頭にゼロが表示されていることを除いて、メインスタックに再び入力があります。は;スタックを破棄して0から=スタックの先頭=を交換しますが、ループの最初の部分をキャンセルするだけです。これは、現在別の場所からループに入っているからです。すすぎ、繰り返します。


3

sed、67 61バイト

G;H;:1;s/\(.\)\(.*\n\)/\2\1/;t1;y/ACGT/TGCA/;G;s/^\(.*\)\1$/1/;t;c0

(67バイト)

テスト

for line in ATCGCGAT AGT GTGACGTCAC GCAGTGA GCGC AACTGCGTTTAC ACTG
do echo -n "$line "
    sed 'G;H;:1;s/\(.\)\(.*\n\)/\2\1/;t1;y/ACGT/TGCA/;G;s/^\(.*\)\1$/1/;t;c0' <<<"$line"
done

出力

ATCGCGAT 1
AGT 0
GTGACGTCAC 1
GCAGTGA 0
GCGC 1
AACTGCGTTTAC 0
ACTG 0

拡張正規表現を使用すると、バイトカウントを61に減らすことができます。

sed -r 'G;H;:1;s/(.)(.*\n)/\2\1/;t1;y/ACGT/TGCA/;G;s/^(.*)\1$/1/;t;c0'

あなたが61バイトでそれを行うことができれば、それはあなたのスコアです-この特定のチャレンジでNFAまたはチューリング完全正規表現に対して何もありません。いくつかの課題がいっぱいに正規表現を許可しないが、通常は正規表現のゴルフは、非禁止します通常の -expressionsを。

3

C#、65バイト

bool F(string s)=>s.SequenceEqual(s.Reverse().Select(x=>"GACT"[("GACT".IndexOf(x)+2)%4]));

.NETには、かなり長いフレームワークメソッド名が含まれている場合がありますが、これは必ずしも最高のコードゴルフフレームワークになるとは限りません。この場合、フレームワークメソッド名は90文字のうち33文字です。

スレッドの他の場所からのモジュラストリックに基づく:

bool F(string s)=>s.Zip(s.Reverse(),(a,b)=>a%8+b%8).All(x=>x%5==0);

これで、13文字がメソッド名である67文字になります。

なんと2文字を削る別のマイナーな最適化:

bool F(string s)=>s.Zip(s.Reverse(),(a,b)=>(a%8+b%8)%5).Sum()<1;

したがって、65個のうち13個はフレームワーク名です。

編集:ソリューションから制限された「定型」の一部を省略し、いくつかの条件を追加すると式が残ります

s.Zip(s.Reverse(),(a,b)=>(a%8+b%8)%5).Sum()

これは、文字列sが有効な答えである場合にのみ0を返します。catが指摘しているように、「bool F(string s)=>」は、コードで式がa であることが明確であれば、実際には「s =>」に置き換え可能ですFunc<string,bool>。文字列をブール値にマップします。


1
PPCGへようこそ、最初の回答です!:D-

@catそれをありがとう!:)
robhol

1
私は本当に C#を知りませが、これがラムダである場合、匿名関数は割り当て可能であれば問題ないので、その型を省略して割り当てることができます。

1
また、!s.Zip...代わりにできませんs.Zip...==0か?(または!、C#でint できませんか?)ブール否定できない場合でも、偽りや<this other deterministicに対して<this thing>を返すという、あらゆる種類の反転や状態を回答から除外することができます。明確に識別できるもの>真実のために。

1
@cat:型を削除するのは正しい。コードは直接実行可能でなければならないと思っていましたが、入力と出力について簡単に仮定することで少し簡単になりました。しかし、他のことは機能しません-私の意見では、ブール演算には数値に適用する論理的な(色相)方法がないため、当然です。0と1にfalseとtrueの値を割り当てることは、結局のところ単なる慣習です。
ロブール


2

R、101バイト

g=function(x){y=unlist(strsplit(x,""));all(sapply(rev(y),switch,"C"="G","G"="C","A"="T","T"="A")==y)}

テストケース

g("ATCGCGAT")
[1] TRUE
g("AGT")
[1] FALSE
g("GTGACGTCAC")
[1] TRUE
g("GCAGTGA")
[1] FALSE
g("GCGC")
[1] TRUE
g("AACTGCGTTTAC")
[1] FALSE
g("ACTG")
[1] FALSE

strsplit(x,"")[[1]]unlist(strsplit(x,""))x常に単一の文字列であるため、よりも3バイト短く、ここでは同等です。
プランナパス

2

オクターブ、52バイト

f=@(s) prod(mod((i=mod(toascii(s),8))+flip(i),5)==0)

Denisのトリックに続いて、ASCII値mod 8を取得し、反転して加算します。すべての合計が5の倍数である場合、ゴールデンです。


その1つの空白が重要なのですか?それは変です。

また、f=割り当てを省略できます。名前のない関数は大丈夫です。

1

Clojure / ClojureScript、49文字

#(=(list* %)(map(zipmap"ATCG""TAGC")(reverse %)))

文字列で動作します。リストを許可するために要件が緩和されている場合は、(list* )7文字を節約できます。


1

R、70バイト

f=function(x)all(chartr("GCTA","CGAT",y<-strsplit(x,"")[[1]])==rev(y))

使用法:

> f=function(x)all(chartr("GCTA","CGAT",y<-strsplit(x,"")[[1]])==rev(y))
> f("GTGACGTCAC")
[1] TRUE
> f("AACTGCGTTTAC")
[1] FALSE
> f("AGT")
[1] FALSE
> f("ATCGCGAT")
[1] TRUE

1

C、71バイト

関連する文字にASCIIコードが必要ですが、大文字、小文字、または大文字と小文字が混在した入力を受け入れます。

f(char*s){char*p=s+strlen(s),b=0;for(;*s;b&=6)b|=*--p^*s++^4;return!b;}

このコードは2つのポインタを保持し、sかつp、反対方向に文字列を横断します。各ステップで、対応する文字を比較し、一致bしない場合はtrue に設定します。マッチングは、文字値のXORに基づいています。

'A' ^ 'T' = 10101
'C' ^ 'G' = 00100

'C' ^ 'T' = 10111
'G' ^ 'A' = 00110
'A' ^ 'C' = 00010
'T' ^ 'G' = 10011
 x  ^  x  = 00000

上記の表を見ると、xx10x他のすべての成功と失敗を記録したいので、00100(4)でXORし、00110(6)でマスクして、そうでなければ0を取得しATCGそうでなければ0以外を取得します。最後に、すべてのペアがゼロを蓄積した場合はtrueを返しb、そうでない場合はfalse を返します。

テストプログラム:

#include <stdio.h>
int main(int argc, char **argv)
{
    while (*++argv)
        printf("%s = %s\n", *argv, f(*argv)?"true":"false");
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.