Skip to content

Instantly share code, notes, and snippets.

@tjkendev
Last active February 3, 2023 01:29
Show Gist options
  • Save tjkendev/63df75a6831119791ed1a657bc4c1988 to your computer and use it in GitHub Desktop.
Save tjkendev/63df75a6831119791ed1a657bc4c1988 to your computer and use it in GitHub Desktop.
ショートコーディングのためのtipsまとめ
  • 基本
3**3  # => 9
3x3   # => "333"
"a"x3 # => "aaa"
1."a" # => "1a"

# 文字列や数値は随時キャストされる
10 x 3 * 5    # => 505050
"1a" * 3      # => 3
"" * 3        # => 0
"a" * 3       # => 0
3 * '4'       # => 12
"1.1" + "3.3" # => 4.4
int "1.3"     # => 1
int "-2.3"    # => -2

# Scalar Variables
$a = 1
# Array Variables
@a = (1, 2, 3)
$a[1]   # => 2
$b = @a # => 3 (要素数)
# Hash Variables
%a = (a, 1, b, 2)
$a{a}      # => 1
keys(%a)   # => (b, a)
values(%a) # => (2, 1)
$b = %a    # => 2 (要素数)
  • 変数
# $$変数
$v = "abc";
$$v = 100;  # => $abc = 100 と同じ

$v = -10
$$v = 200;  # => ${-10} = 200 と同じ

$v = 10
$$v = 300;  # => $10 = 300 と同じ
# --> エラー (正規表現のsubpattern用変数でread-only)
  • 入出力
# 入力
$x = <STDIN>
$y = <>

# 出力
print "Hello" # => 出力: "Hello"
print         # => "$_"."$\" が出力される
say "Hello"   # => 出力: "Hello\n" ("use feature" が必要?)
  • 文字列処理
# glob関数
# 引数は空白区切りで、文字範囲やワイルドカードを含むファイル名
# 引数のワイルドカードが指定されてない場合、文字列がリストとして返される
# => 特定の入力に対し、文字列をsplitして返してくれるものとみなせる
glob "10 20 30" # => ("10", "20", "30")
  • 配列処理
# map関数
map { $_ * 2 } (1, 2, 3)  # => (2, 4, 6)
map(($_, $_*2), (1, 2, 3) # => (1, 2, 2, 4, 3, 6)

# join, split
join(',', (1, 2, 3)) # => "1,2,3"
split(',', "1,2,3")  # => ("1", "2", "3")
  • 正規表現マッチ
# マッチする文字列が含まれるか
"abcdef" =~ /de/ # => 1
"abcdef" =~ /bd/ # => ''
# マッチする文字列が含まれていないか
"abcdef" !~ /de/ # => ''
"abcdef" !~ /bd/ # => 1

# gオプションでマッチするもの全てをリストとして返す
"adbbcded" =~ /.d/g # => ('ad', 'cd', 'ed')

# 置換処理
$a = "abcdef"
$a =~ s/[bcd]/e/g # => 3
$a                # => "aeeedf"
$b = "abcdef"
$b =~ y/bcd/123/g # => 3 (tr/bcd/123/g も同じ)
$b                # => "a123ef"

# デフォルト引数
$_ = "abcdef"
/bcd/      # => 1

$_ = 12345
s/[24]/6/g # => 2
$_         # => 16365
  • 特殊変数
# デフォルト引数: $_
$_ = 'abc'
chop
$_   # => 'ab'
say  # => 出力: "ab\n"

# 現在の入力行番号: $.
# ** 入力を行った回数とみなせる?
$/=' ';1 while <>; print $. # 入力: '1 4 9' => 出力: 3

# input record separater: $/
# ** デフォルト値: "\n"
$/ = ' ';    # (' 'を入力の区切りとして認識)
print <>-<>; # 入力: "1 2" => 出力: -1

# output record separater: $\
$\ = 'x';     # ('x'を出力の区切りとして認識)
print "test"; # => 出力: "testx"
print 123;    # => 出力: "123x"

# output list separater: $"
# ** デフォルト値: " "
@x = (1, 2, 3);
print "@x"; # => 出力: "1 2 3" ($" = ' ')
$" = "x";
print "@x"; # => 出力: "1x2x3"

# output field separater: $,
$, = "x";
print (1, 2, 3); # => 出力: "1x2x3"

# マッチングした文字列: $&, 最後の括弧でマッチングした文字列: $+
"ab129cd" =~ /([0-9]+).*d/
print $&; # => 出力: "129cd"
print $+; # => 出力: "129"

# マッチング前後の文字列: $`, $'
"1 2 3" =~ " ";
print "$`+$'";  # => 出力: "1+2 3"

# 1ページの残りの行数: $-
# ** 負の値は0になる
$- = -10 # => 0 (負の値は0に)

# 1ページあたりの行数: $=
# ** 常にintにキャストされる
$= = 'abc' # => 0
$= = 1.5   # => 1

# 総出力ページ数: $%
# ** $%のあとにifやwhileが繋げられる変数として利用可能
$%=<>; print$_*$%for 1..5

参考: http://www.perlmonks.org/?node_id=353259


  • Pythonの強み

    • True == 1であること
      • True + True => 2
    • print関数で複数の引数を与えると空白区切りになる
      • print(1,2)1 2が出力される
    • 比較演算子が繋げて書ける
      • 0 < x < 100 > y > 0 == z みたいな書き方が可能
  • Pythonの弱み

    • ループ文が簡易に書けない
      • 基本 for - in 形式
    • 代入文が式中に書けない
      • a = (b = 1) + 1 などができない
    • 入力の受け取り
      • 空白区切りの一行は基本的には map(int, raw_input().split())
    • ラムダ式: lambda x: f(x)
      • 簡略的な書き方ができない (Rubyの->{}のような記述はない)
      • 内部に複数の式文を含めることができない
    • &&, ||, !が使えない
      • andor , notを使う
      • 前後に他の関数を空白なしでは繋げられない

>> Python2, Python3 共通

  • 入力一括取得
# 入力の数値が改行区切りのみであれば有効
# 入力: "1\n2\n3\n4\n" => A = [1,2,3,4]
import sys
A=map(int,sys.stdin)
  • execによる記述短縮
# ループ文の短縮 (ただしexec文が処理する文字列が多いとつらい)
for _ in range(n):f()
for _ in[0]*n:f()
exec"f();"*n

# if文簡略
exec["f()","g()"][a==b] # "a==b"の真偽でどちらを実行するかが決定
exec"f()"*(a==b)        # => "a==b"が真の時のみ"f()"が実行される
  • evalによる記述短縮
# 改行で区切られたn個の数値を配列で取得
[input()for i in xrange(n)] # => [input(), ...]
[input()for i in[0]*n]      # => [input(), ...]
eval("input(),"*n)          # => tuple([input(), ...])

# 3*4の2次元配列生成
[[0 for i in range(4)] for j in range(3)]
[[0]*4for i in[0]*3]
eval(`[[0]*4]*3`)
eval("[0]*4,"*3)  # => tuple([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])
  • +1, -1における括弧の省略
# "(x+1)" => -~1, "(x-1)" => "~-1"
# "(x+1)*2" を "-~x*2" のように書ける
print x+1
print-~x
  • True, False --> 0, 1
+True  # 1
-True  # -1
+False # 0
+(1<2) # 1
  • 括弧の省略
a=1,  # => a = (1,)
a=1,2 # => a = (1,2)
  • A.extend vs A+=[]
A = []

A.extend([4,5,6])
A+=4,5,6 # A+=[4,5,6]と等価

A.append(7)
A+=7,    # => A+=[7]と等価
  • setの扱い
a = {1,2,3} # a = set([1,2,3])
p,q,r = a   # p = 1, q = 2, r = 3

b = {1}
c, = b      # c = 1
  • and, orの活用
# aとbが等しければ"YES", 等しくなければ"NO"を出力
print"YES"if a==b else"NO"
print["NO","YES"][a==b]
print"YES"*(a==b)or"NO"

# Bが0以外でなければf()を評価したくない場合
B and f()

# and, orの前が数値ならばスペースを省略しても問題ない
print 1and 2 # 出力: "2\n"
print 1or 2  # 出力: "1\n"
  • lambdaの活用
# 長い処理をコード中何回も呼び出す場合に有効
i=lambda:map(int,raw_input().split())
i();i();i()
  • 関数のリネーム
i=input
i()
j=" ".join
j(["1","2"]) # => "1 2"
  • モジュールimport
from heapq import*
from heapq import heappush as h
  • タブ1インデント
if A:
 print B # tab 1
  • 関数定義
def f(*a):return a
f(1,2) # => (1,2)
f()    # => ()
f=lambda*a:a
f(3,4) # => (3,4)

def g(**a):return a
g(a=1,b=2) # => {'a': 1, 'b': 2}
g(a=1)     # => {'a': 1}
g()        # => {}
g=lambda**a:a
g(c=3)     # => {'c': 3}

def h(*a,**b):return[a,b]
h(0,1,a=1) # => [(0, 1), {'a': 1}]
h()        # => [(),{}] 

>> Python2のみ

  • 括弧省略
print-1   # => print(-1)
exec"a=1" # => exec("a=1")
  • repr(x) => `x`
`1` # => repr(1)
x = 1
`x` == str(x) # => True

`id` # => '<built-in function id>' (22文字)
  • リスト内部に対する関数引数
def f((a,b,c)):
    print a, b, c
A=[1,2,3]; f(A) # => 出力: "1 2 3\n"
  • 数値以外との数値比較
# Noneは-inf、(),[],関数などは+infとして扱える
None < 1 # => True
1 < ()   # => True
1 < len  # => True
  • Leaked variable
# 変数定義はループの外でも有効
[i for i in range(100)]
i # => 99
[m(int,raw_input().split())for m in[map]*10]
m # => mapとして使える
  • 関数cmp (宇宙船演算子(spaceship operator)に対応)
cmp(0,1) # => -1
cmp(1,1) # => 0
cmp(1,0) # => 1

Python2と基本同じであるが、大きな仕様の違いからより短くすることができる。(逆に長くなる場合もある)

  • ショートコーディングにおいて影響する仕様の変更点
    • printの関数化 (PEP 3105), execの関数化
      • 括弧が必要になった, 最大2文字増える
    • xrange => range
      • イテレータが1文字短く書ける
      • rangeでリストが直接生成できない => listに変換する必要がある
    • raw_input => input
      • 文字列入力が4文字短く書ける
      • 数値受け取りは一度intで変換する必要がある
    • mapがイテレータを返す
      • listに変換する必要がある
    • Extended Iterable Unpacking (PEP 3132)
      • a, *b = [1,2,3] => a = 1, b = [2, 3]
    • Removal of Tuple Parameter Unpacking (PEP 3113)
      • 関数引数のリスト内はbody内で参照する必要がある
    • 除算 / がfloatを返す
      • 整数を返して欲しい場合は/ではなく//を用いる, 1文字増える
      • 1/2 => 0.5, 1//2 => 0

参考: What’s New In Python 3.0


  • 入力一括取得
x,y,*A=open(0).split()
  • 括弧の省略
a=1, # a = tuple(1)
a,*b=1,2,3 # => a = 1, b = [2,3]
  • tuple, generator => list
# tupleをlistに変換
T=[*(1,2,3)]
*T,=(1,2,3)

# map objectをlistに変換
X=[*map(int,input().split())]
*X,=map(int,input().split())
*X,=range(1,n)
  • print文
# 改行なしで出力
print("abc",end='')  # => 出力: "abc"
print(end="abc")     # => 出力: "abc"

# 一つ一つスペース空けて出力
A=[1,2,3]
print(" ".join(map(str,A))) # => 出力: "1 2 3\n"
print(*A)                   # => 出力: "1 2 3\n"

# 一つ一つ","区切りで出力
A=[1,2,3]
print(",".join(map(str,A))) # => 出力: "1,2,3\n"
print(*A,sep=',')           # => 出力: "1,2,3\n"

# 一つ一つ改行して出力
X = [1,3,5,7]
print("\n".join(map(str, X)) # => 出力: "1\n3\n5\n7\n"
for x in X:print(x)          # => 出力: "1\n3\n5\n7\n"
*_,=map(print,X)             # => 出力: "1\n3\n5\n7\n"
[*map(print,X)]              # => 出力: "1\n3\n5\n7\n"
  • ループの記述
(0..3).each{|i| print i}  # => 出力: "0123"
3.times{|i| print i}      # => 出力: "012"
0.upto(3){|i| print i}    # => 出力: "0123"
3.downto(3){|i| print i}  # => 出力: "3210"
0.step(9,3){|i| print i}  # => 出力: "0369"

(0..3).map{|i| i}  # => [0, 1, 2, 3]
(0...3).map{|i| i} # => [0, 1, 2]
3.times.map{|i| i} # => [0, 1, 2]

[1,2,3].each_cons(2){|a| print a}  # => 出力: "[1, 2][2, 3]"
[1,2,3].each_slice(2){|a| print a} # => 出力: "[1, 2][3]"

"abc".chars {|c| print c*2} # => 出力: "aabbcc"
  • shコマンドによる短縮記述
# `tr`コマンドを使って定数にsplitした数値の結果を代入
eval"X,Y="+`tr ' ' ,`
X,Y=gets.split.map &:to_i # と同じ

# `dd`コマンドを使って入力を一括取得
x,y,*A=`dd`.split
x,y,*A=$<.read.split # と同じ
  • global variablesによる記述短縮
$> # => #<IO:<STDOUT>>
$< # => ARGF

$><<"ABC" # print "ABC"
$/=' ';A,B,C,D=$<.map &:to_i # stdin = "1 2 3 4" => A,B,C,D=[1,2,3,4]

A=$<.map &:to_i # stdin = "1\n2\n3\n" => A =[1,2,3]
A=*$<           # stdin = "1\n2\n3\n" => A = ["1\n", "2\n", "3\n"]

参照: https://docs.ruby-lang.org/ja/latest/doc/spec=2fvariables.html

  • symbolによる文字列記述短縮
?A   # => "A"
:ABC # => :ABC (putsで"ABC"になる)
  • &&,||評価の利用
# x==yでない場合のみにz=3が評価される
x==y||z=3
  • 正規表現の利用
a="abc"
a=~"c" # -> 2
a=~"d" # -> nil
"1\n2-3".split(/[
-]/)   # -> ["1", "2", "3"]

参考: https://docs.ruby-lang.org/ja/latest/doc/spec=2fregexp.html

  • Stringのメソッド利用
"abc"["ab"] # => "ab"
"abc"["ac"] # => nil
"abc"[/a./] # => "ab"

参考: http://ref.xaio.jp/ruby/classes/string/element_ref

  • Fixnumのメソッド利用
# 2進数文字列への変換
37.to_s(2)           # => "100101"
37.to_s(2).count(?1) # => 3
# bit参照
37[2] # => 1 (= (37 >> 2)&1 )
# gcd, lcm
12.gcd(18) # => 6
12.lcm(18) # => 36
  • Arrayのメソッド利用
# 集合計算
[2,3,1] & [2,1,4,5] # => [2, 1] (積集合)
[2,3,1] | [2,1,4,5] # => [2, 3, 1, 4, 5] (和集合)
[2,3,1] - [2,1,4,5] # => [3] (差集合)
[1,2].product([1,2]) # => [[1, 1], [1, 2], [2, 1], [2, 2]] (直積集合)

# 要素の追加
a = []
a += [1]       # => [1]
a<<2           # => [1, 2]
a.push(3,4)    # => [1, 2, 3, 4]
a.unshift(5,6) # => [5, 6, 1, 2, 3, 4]

# 配列内の特定の要素の数を計算
[1,2,3,1,2].count(1)        # => 2
# 配列内の、特定の条件を満たす要素の数を計算
[1,2,3,1,2].count{|e|e%2>0} # => 3
# 配列内の、特定の条件を満たす要素のみの配列を返す
[1,2,3,1,2].select{|e|e%2>0} # => [1,3,1]
# 配列内の、特定の条件を満たさない要素のみの配列を返す
[1,2,3,1,2].reject{|e|e%2>0} # => [2,2]
  • ラムダ関数の利用
F=->x{f(x)}
G=lambda{|x|f(x)}
F.call x
F[x]

I=->{gets.split.map &:to_i}
a,b,c=I[]
  • 出力方法の選択
p 1             # => 出力: "1\n"
puts"abc"       # => 出力: "abc\n"
putc 97         # => 出力: "a"
print 1         # => 出力: "1"
puts[1,2,3]*' ' # => 出力: "1 2 3\n" (= [1,2,3].join ' ')
  • sprintfフォーマット
52.to_s(2) # => "110100"
"%b"%52    # => "110100"

eval"p %d+%d"%gets.split # 入力: "1 2\n" => 出力: 3

参考: https://docs.ruby-lang.org/ja/latest/doc/print_format.html

  • 評価順序の利用
a<a+=1 # => true

参考: Ruby4章後半(演算子)- Slideshare, Ruby operator precedence table - Stack overflow


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment