`range(…)`のより短い代替案を探しています


8

私が取り組んでいるゴルフコードパズルについてこれまでに見つけた最良の解決策には、2つのかなり太っているような呼び出しがありrangeます。私はコードゴルフ、特にPythonが初めてなので、いくつかのヒントを使うことができます。

関連フラグメントはこれです

[x for x in range(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in range(2,x))]

最初の上限はrange鋭いものではありません。それは少なくとも98690である必要があり、他のすべてが等しい場合(ゴルフの場合、つまり)、この上限と98690の差が小さいほど、パフォーマンスの点で優れています1。私が7 6(= 117649)を使用しているの7**6は、私が思いつくことができる最も短いPython式であり、それが法案に合うからです。

対照的に、range1つ目の下限と2つ目の下限はどちらもしっかりしています。IOW、これらの制限が変更されると、プログラム(現在の形式)は誤った結果を生成します。

式の一方または両方を短くする方法はありますか

range(n+1,7**6)
range(2,x)

ところで、この場合range、たとえばへのエイリアスrは何も得ません:

r=range;rr
rangerange

編集:FWIW、完全なプログラムはこれです:

p=lambda n:[x for x in range(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in range(2,x))][0]

p(n)より大きい最小の回文素数である必要がありnます。また、p再帰的であってはなりません。警告:すでに卑猥に遅いです!


1はい、わかっています。コードゴルフではパフォーマンスは重要ではありませんが、それが私が「他のすべてが等しい(ゴルフに関しては)」と書いた理由です。たとえば、私が選択したのは7**6、すぐにはわかりませんが、パフォーマンスが低く、「ゴルフと同等の」代替手段9**9です。私は実際にコードゴルフの試行を実行するのが好きです。つまり、コードを実行するのに何年もかかるほどパフォーマンスが低下しないようにします。もちろん、私がそれを助けることができれば。


1
fwiw、ジェネレーターを使用することで、テスト目的ではるかに速くすることができます。それ以外は同等ですp=lambda n:(x for x in xrange(n+1,7**6)if`x`==`x`[::-1]*all(x%i for i in xrange(2,x))).next()。もちろん、その間、テストをに変更xrange(2,x)xrange(2,int(x**.5+1))てテストを非常に高速にすることもできます。明らかに、このコードはあなたのものと同等ですが、より長く、より高速です。
ジャスティン

1
コンテキストから分離された短いフラグメントで多くの優れたゴルフトリックを思いつくことは不可能です。最も優れたプログラムは、プログラムのさまざまな部分の間で驚くべきつながりを作ることがよくあります。たとえば、一見役に立たないように破棄された変数が鍵になるか、2つの無関係なループが1つに結合されていることがわかります。
feersum 14年

@feersum:かなり前に(EDITで)すべてを投稿しました。コメントを投稿する前でした。見えなかったの?
kjo 2014年

@FryAmTheEggman:はい、パズルのステートメントはそれが関数でなければならないということであり、さらに悪いことに、関数は再帰的であってはなりません。
kjo 2014年

1
あなたはここ
ベータ崩壊

回答:


7

単一のループにする

現状では、ループが2つあります。1つは繰り返しx文法素数である可能性があり、もう1つは試行錯誤による素数iかどうかを確認するために繰り返しxます。お気づきのように、ループはPythonが多くの文字を取り、多くの場合、を書き込むだけrangeでなく、while _:またはを書き込むこともありfor x in _ます。したがって、ゴルフされたPythonソリューションでは、できるだけ少ないループを使用するのに苦労する必要があります。

feersumのコメント「最高のゴルフプログラムは、プログラムのさまざまな部分の間で驚くべきつながりを作ることがよくある」は、ここで非常に当てはまります。プライムチェックall(x%i for i in range(2,x))は、古典的な表現である別のサブルーチンのように見えるかもしれません。しかし、別の方法で行います。

アイデアは、ウィルソンの定理を使用することです。潜在的な素数ごとにk、の実行中の積を保持し、(k-1)!それがの倍数であることを確認しkます。稼働中の製品を維持することで、主な回文構造になる(k-1)!可能性をテストしながら追跡できkますP

実は、私たちは、ウィルソンの定理の強いバージョン使用します(k-1)! % kコンポジットのため0に等しいk除き、唯一の合成数のためにk=4与え2、そしてそう(k-1)!**2 % k等しい0合成数のために正確に。update Pを使用しk!**2て、equal に更新しP*=k*kます。

(参照してくださいこの回答を Pythonで素数を見つけるために使用されるこの方法のため。)

すべてを一緒に入れて:

def p(n):
 k=P=1
 while(`k`!=`k`[::-1])+(k<=n)+(P%k==0):P*=k*k;k+=1
 return k

これはまだ完全にはゴルフされていません-特に条件は非効率的に書かれています。条件を圧縮して、それkが回文であることを確認すると同時に、連鎖不等式によって他の条件を強制することができます。

def p(n):
 k=P=1
 while`k`*(P%k>0>n-k)!=`k`[::-1]:P*=k*k;k+=1
 return k

1
見事なソリューション。私の手の届かない領域に入ったとしても、私はそれを見て感謝しています...これまでのゴルフの改善はすべて、の代わりにバックティックを使用するなどのトリックを拾うことでしたstrが、これらのトリックは1つしか得られません多くの...いつものように、大きな改善はより良いアルゴリズムから来ています。
kjo 2014年

1
FryAmTheEggmanの解法に従って、条件をとして書き換えることができます。これにより、`k`*(k>n)*(P%k>0)!=`k`[::-1]4を
削ります

1
@kjoはい、不等式を1つに連鎖させれば、さらに似ています。また、Python Golf Practiceもチェックして、このようなトリックを確認してください
xnor

それはとてもうまくやった!皆さん、ありがとうございました!これは私にとって非常に目を見張るようなスレッドでした... Python 2.7と3.3で私が知っている最短のソリューションの長さは、それぞれ、最初に投稿したバージョン(私の最善の努力)よりも28文字と32文字短くなっています。私がこれについて知ったとき、私は信じられませんでした。(たとえば、自動化されたソリューションテストプログラムをリバースエンジニアリングすることによって)どこかで不正なプレイが必要だと思いました。しかし、ここの専門家が私の最善の努力からどのようにして最大16文字まですばやく削ったかを見て、今ではそれらの数字を信じる用意があります。
kjo 2014年

@kjoゴルフの魔法が魔法のように見えてうれしいです。55文字の解決策があると言いますか?もしそうなら、私は興味をそそられます。これはアナーキーゴルフの問題ですか?問題の説明にリンクしていただけませんか。具体的には、テストケースに番号4で例外のギャップから可能なショートカットがあるかもしれません
XNOR

3

私の知る限りではありません。

範囲は、増加または減少する数値のリストを生成する最短の方法であるため、Pythonゴルフで一般的に使用されます。

とはいえ、範囲の使用を避けるために少し(7バイト)短いように見え、代わりにラップされたwhileループを呼び出します。

def p(n):
    n+=1
    while`n`*all(n%i for i in range(2,n))!=`n`[::-1]:n+=1
    return n

(いつものように)while条件のロジックを改善してくれた@xnorに感謝します:)


ノートラブル@kjo :)あなたはそれが別段、この答えはかなり悪く、質問への非再帰関数であることを持っていることについて私に言ったものを追加したいかもしれません。)
FryAmTheEggman

2
暗黙的に否定することにより、条件を節約できますwhile(`n`!=`n`[::-1])+0in(n%i for i in range(2,n)):n+=1。演算子の優先順位の問題により、最初のペアの括弧を取り除くことができないようです。
xnor 2014年

2
while`n`*all(n%i for i in range(2,n))!=`n`[::-1]:n+=1
かっこ

@FryAmTheEggman:それはあなたのスポーツマンのようなものです!完了
kjo 2014年

1

ニュートン法やフラクタルの計算などの反復アルゴリズムを使用する場合、通常は実際にインデックス気にせずに反復実行する必要がありますが代わりに短い文字列を反復することで一部の文字を保存できます。

for i in range(4):x=f(x)
for i in'asdf':x=f(x)

7回の反復で、これはでも中断しrangeます。反復回数を増やすには、backticsと大きな数値を使用します

for i in`9**9**5`:pass

これは56349回実行され、実際の目的には十分です。数値と演算子をいじってみると、この方法で幅広い数値をハードコードできます。


これは興味深いものですが、彼がインデックスを気にしていることがはっきりとわかります(候補となる素数がインデックスであるため)。私は、このフィットが良いの一部として考えて、この答え :)代わりにヒントのページに(またノート'1'*4よりも短くなっている'asdf'
FryAmTheEggman
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.