Kinesis Advantage2LF (赤軸)の設定

第一印象

かなり大きくて邪魔になることを覚悟していたけれど、机に置いてみるとそれほどでもない感じ。これまでキーボードの左に置いていたトラックパッドを上に載せることができるので、奥行は少し長くなるけど幅はほとんど変わらない。

アルファベットと数字については、2,3 時間で大体問題ないくらいには慣れることができた。問題は一部の記号とCtrl, Altなどのモディファイアの位置。

  • 比較的よく使う[], {}の位置が変わっており、右手の薬指・小指で押す必要がある
  • これまではAltなどの位置を体が覚えていたが、それが全てリセットされてしまい覚え直す必要がある。

なので、マニュアルに書いてあるように慣れるには数週間はかかりそう。

f:id:kichi941:20171117220927j:plain f:id:kichi941:20171117220544j:plain

最初の設定

デフォルトのキー 配列ではとても使えないので、以下のように変更して使用開始。

  • ESCが遠すぎるので、近くにもってきた
  • 矢印キーは、viっぽく右手側にまとめた
  • emacsを使うので、Aの隣りにCtrlが必要
  • とはいえ、せっかくなので親指でもCtrlを押せるようにして小指の負荷を減らしたい
  • 親指キーは覚えやすいように左右対称からスタート
  • BackSpaceはC-h, C-dで代用できるので、一番押しづらい位置でOK

f:id:kichi941:20171117221348j:plain

3日目の設定

  • Enterが近くにないと不便なので、右手のデフォルト位置に戻した
  • キーボード側のマクロ機能を使用して、IMEのON/OFF(CMD-Space)を割り当てた f:id:kichi941:20171117223120j:plain

5日目の設定

Karabiner-Eelementsを使用すると複数のキーを一つにまとめることがができることが分かったので、早速設定した。

  • 両方のScapeをSpace and Shift化した
  • 左CtrlとESC、右CtrlとEnterをワンショットモディファイア化してまとめた
  • 親指のCtrlに独自キーを割り当てる必要がなくなったので、Altとして使用
  • DeleteをAltに変更していたが、単独のBackSpaceにする f:id:kichi941:20171117223740j:plain

7日目の設定

Karabiner-Elements用のjsonファイルの書き方がなんとなく分かってきたので、独自設定のテスト。

  • BackSpaceとAltを兼用にする
  • 矢印キーをvi風にすると、使用時に手をホームポジションから大きく動かさないといけないので、普通の上下左右の順番に変更
  • ウィンドウの切り替え(CMD-Tab, CMD-ESC)がやりやすいように、ESCとTabを親指に配置

f:id:kichi941:20171117225120j:plain

11/24時点での設定

  • Commandキーもワンショットモディファイア化して、単キーでアプリを切り替えられるようにした

f:id:kichi941:20171124195656j:plain

現在の問題点

  • 調子にのって親指のキーをワンショットモディファイア化しまくっているため、親指の負担が大きい → 1週間使ってみたが問題なし
  • 元々のShiftキーが完全に遊んでいる → でも、このキーを使用すると小指への負荷が大きそう
  • 親指から一番遠いキーは無駄にマウスクリックを割り当てているが、もっと有効な設定にしたい
  • 元々Endキーがあった部分がCMD-Tabのまま遊んでいるので、何か割り当てる

PyCharmのプラグインEMACS+を試す

前回に続き、JetBrainsのIDEをよりemacsっぽく使う方法のメモ。

機能概要

keymapの設定に、よりemacs風になった「Emacs+」と「Mac Emacs+」が追加されます。

キーマップが追加されるだけなので、これを選択しないと何も変わりません。[Preferences]-[Keymap]から追加されたキーマップを選択することで有効になります。 f:id:kichi941:20161224215946j:plain

プラグインの入手

[Preferences]を開き[Plugins]を選択します。その中にある[Browse repositories...]ボタンを押し、「EMACS+」で検索してインストールします。 f:id:kichi941:20161224194719j:plain

お試し結果

かなりemacsっぽくなりました。特に便利なのが以下の2点。

  • C-l による現在行表示位置の移動

従来の「emacs」キーマップでは、C-lで現在行が画面の中央にくるだけでした。Emacs+にすることで、C-lキーを押すたびにカーソル行が、画面の中央→1行目→最終行→画面の中央→… になるように表示されます。

  • M-; によるコメント入力

たとえばpythonで「raise ValueError」という行があってM-;を押した場合、従来のEmacsキーマップでは[Comment with Line Comment]機能が割り当てられているので、以下のように丸ごとコメントアウトされていました。

    # raise ValueError

これがEmacs+では以下のようになり、すぐに行末にコメントを入力できるようにしてくれます。

    raise ValueError            #  ←カーソルはここにくる

以下に詳しい説明があります。

JetBrains Plugin Repository :: Emacs+

現在のところ判明している問題点は以下の通り。

  • プログラムを実行(Run)しているウィンドウで、ペースト(C-y)が動かない。

メモ

EMACS+と似た名前のemacsIDEAsというプラグインもあります。こちらの方がダウンロード数も多くAceJump相当の機能を内包しているなど多機能そうなのですが、既存のキーマップと相性が悪そうなので使用を断念しました。

キーマップをデフォルトで入っている「Emacs」にしているとうまく動作せず、「Mac OS X」など他のキーマップにする必要があるようです。これだと「C-<Space>で範囲選択開始」などを全て自分で設定する必要があり面倒なので試すのをやめてしまいました。

PyCharmのプラグインAceJumpを試す

PyCharmにもようやく慣れてきました。開発環境としてはemacsよりもPyCharmを触っている時間の方が長くなってきたので、冬休み中に本格的に環境構築を行なうつもりです。その中でいろいろな拡張機能を試したのでメモとして残しておきます。

機能概要

画面上の任意の場所に、少ない手間でカーソルを移動できます。

プラグインの入手

[Preferences]を開き[Plugins]を選択します。その中にある[Browse repositories...]ボタンを押し、「AceJump」で検索してインストールします。 f:id:kichi941:20161224194719j:plain

お試し結果

必須、もうこれ無しでは生きていけません。

これまでは、移動したい単語を[Find]や[Find Previous]で検索することでカーソルを移動させていました。しかし、プログラムを作成していると変数の宣言・変数への代入・変数値による条件分岐 などで同じ名前が何度も登場するので、何度も検索する必要があり移動に手間がかかっていました。

AceJumpを使用することで、数回のキー入力で画面上のどの位置にでも移動できます。

たとえば下のソース例では、’max_score’という名前が何度も出てきます。この状態でAceJumpを起動(デフォルトのショートカットはC-;)して’m’をタイプすると、mが含まれる場所に[Q], [W], [NB] などのコードが割り振られます。このコード(小文字でOK)をキーボードから入力することで、希望する場所にジャンプすることができます。

f:id:kichi941:20161224194913j:plain

プログラムだけではなく、htmlの編集でdivとかclassが大量に出てくる時にも威力を発揮してくれるのではないかと思います。

言葉の説明だとイメージが掴みにくいですが、↓のビデオが分かりやすいです。 https://www.youtube.com/watch?v=yK8eM50DsAY

PyCharmでJavaScriptのデバッグをする


概要

PyCharm(Professional Edition)では、WebStormの機能の多くをカバーしています。プラグインをインストールすることで、WebStorm無しでJavaScriptプログラムのデバッグが可能になります。

なお、以下の説明では、OSとしてMac OS X, デバッグ用のwebブラウザとしてChromeを使用することを想定しています。

注意

無料で使用できるCommunity EditionではWeb development機能が含まれていないため、おそらくこの機能は使用することはできません。 PyCharm Community版とProfessional版の機能比較

事前準備

PyCharmの設定を行なう前に、あらかじめ以下のソフトをインストールしておきます。

PyCharmの設定

PyCharmのメニューから、[Preferences]-[Plugins] を選択します。新しいウィンドウが開くので、[Install JetBrains Plugin...]ボタンを押します。 f:id:kichi941:20161221193658j:plain

プラグインの中から「NodeJS」を選択しインストールした後、PyCharmを再起動します。 f:id:kichi941:20161221193734j:plain

動作確認

PyCharmプロジェクト内のHTMLファイルを右クリックし、[Debug 〜.html]を選択すると、自動的にwebブラウザ(Chrome)が起動します。f:id:kichi941:20161221193819j:plain

PyCharm上のエディタで、JavaScriptソース上にブレイクポイントを設定しておくと、その場所で実行が一時停止状態になり、デバッグできるようになります。 f:id:kichi941:20161221193841j:plain

python3を使用してAOJ(Aizu Online Judge)に挑戦した際にひっかかったこと


計算結果が0.0になってほしいところが、-0.0になってしまう

  • 現象

Volume0 0004 連立方程式用のプログラムを作成した。Sample Input2で期待値が「0.000 3.000」に対して「-0.000 3.000」になってしまう。

  • 原因

浮動小数点演算の誤差?

  • 対策

以下のようなコードを追加して、値が-0.0になった場合、強制的に0.0になるようにする。

from math import fabs
# ...
epsilon = 1e-9
# ...
if fabs(x) < epsilon:
    x = 0.0
if fabs(y) < epsilon:
    y = 0.0

日付から曜日に変換するのが面倒

  • 現象

Volume0 0027 何曜日?で日付から曜日を計算するプログラムを作成した。楽をしようと思ってdatetime.dateを使用して計算したら曜日が一つずれてしまう。

  • 原因

date.weekday()の仕様。このメソッドは月曜日なら0、日曜日なら6を返してくる。月曜日なら1、日曜日なら7を返してほしければ、date.isoweekday()を使用する。

  • 対策

そもそも、date.weekday()/isoweekday()を使って曜日の数字を返してもらい、それを手動で文字列に変換するのが間違っている。date.strftime()を使用して書式に「%A」を指定すれば、曜日を文字列で返してくれる。

標準ライブラリリファレンス: 8.1.8. strftime() と strptime() の振る舞い

from datetime import date
...
    dt = date(2004, month, day)
    print(dt.strftime('%A'))

colloctions.dequeを使用したプログラムでRuntime Errorが発生する。

  • 現象

Volume0 0030 整数の和でプログラムの途中経過を確認するためにdequeを使用した。ローカル環境では完璧に動作しているハズなのに、判定に持っていくとエラーで落とされてしまう。

  • 原因

勘違い。元々のコードでは、dequeに入れてある状態を関数の引数の時の感覚で以下のようなコードでリストに変換していた。ローカルのpython3.5では、この書き方で期待した動作をするが、AOJのpython3.4ではエラーになる。

from collections import deque
# ...
    q = deque()
    q.append(1)
    q.append(2)
    q.append(3)
    status = [*q]  # deque名の前に*を付けると、各要素に展開される???
  • 対策

今回はデバッグ用の箇所でひっかかっていたので3番で。

  1. forループを使用して展開する

  2. dequeを使用せずに、リストで頑張る

  3. 該当コードを削除(コメントアウト)する

pythonでDoubly Linked List

AOJのALDS1_3-C Doubly Linked List に以下のコードで挑戦してみたが、9/10で時間切れで落とされてしまう。

どうやら、insert/deleteXXX操作回数が多くなると性能が出ないらしい。 ローカル環境で操作の進み具合を確認したところ、現在の100倍くらいに高速化しないと制限時間内に終わりそうにない。

仕方がないので、自分で実装するのはあきらめて collections.deque を使用することにする。

# -*- coding: utf-8 -*-
"""
doubly linked list
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ALDS1_3_C&lang=jp
"""
# 9/10 で時間超過になる。

from collections import namedtuple


class DualLinkList(object):
    def __init__(self):
        self.nil = namedtuple('Node', ['key', 'prev', 'next'])
        self.nil.next = self.nil
        self.nil.prev = self.nil

    def insert(self, key):
        x = namedtuple('Node', ['key', 'prev', 'next'])
        x.key = key
        x.next = self.nil.next
        self.nil.next.prev = x
        self.nil.next = x
        x.prev = self.nil

    def listSearch(self, key):
        cur = self.nil.next
        while cur != self.nil and cur.key != key:
            cur = cur.next
        return cur

    def deleteNode(self, t):
        if t == self.nil:
            return
        t.prev.next = t.next
        t.next.prev = t.prev
        # del t

    def deleteFirst(self):
        self.deleteNode(self.nil.next)

    def deleteLast(self):
        self.deleteNode(self.nil.prev)

    def deleteKey(self, key):
        self.deleteNode(self.listSearch(key))

    def get_keys(self):
        results = []
        cur = self.nil.next
        while cur != self.nil:
            results.append(cur.key)
            cur = cur.next
        return results

    def print(self):
        cur = self.nil.next
        while cur != self.nil:
            print(cur.key)
            cur = cur.next


def process_instructions(dll, insts):
    # line_count = 1
    for ins in insts:
        # print('processing line: {0}'.format(line_count))
        # line_count += 1
        try:
            code, key = ins.split()
        except ValueError:
            code = ins
        if code == 'insert':
            dll.insert(int(key))
        elif code == 'delete':
            dll.deleteKey(int(key))
        elif code == 'deleteFirst':
            dll.deleteFirst()
        elif code == 'deleteLast':
            dll.deleteLast()
        else:
            raise ValueError
    return dll.get_keys()



if __name__ == '__main__':
    # データの入力
    num = int(input())
    data = [input() for x in range(num)]
    #data = []
    #with open('ALDS1_3_C_in9.txt') as f:  # ファイルの読み込み
    #    for line in f:
    #       data.append(line.strip())
    #data = data[1:]

    # リストの処理
    dll = DualLinkList()
    results = process_instructions(dll, data)

    # 結果の表示
    print('{0}'.format(' '.join(map(str, results))))

python3を使用してAOJ(Aizu Online Judge)のITP1に挑戦した際にひっかかったこと


Runtime Errorが発生する

  • 現象

ローカル環境ではそれらしく動いていたのに、判定にかけると最初のテストから失敗する。結果は「Wrong Answer」ですらなく、プログラムが全く動作していないように見える。

  • 原因

入力データの受け取り方が間違っている。たとえば、'AA'のような文字が入力されているのに int(input())で整数に変換しようとしている。

  • 対策

プログラムを見直す

ローカル環境では正常に動くのに、ジャッジではRuntime Errorが発生する

  • 現象

ローカル環境では正常に動くのに、評価するとRuntime Errorが発生する

  • 原因

AOJのpython実行環境(3.4.2)にない機能を使用しようとしている。

例: math.gcd(), math.inf, collections.deque.index() はpython3.5以降で使用可能。

  • 対策 プログラムを見直す

pycharmのデバッガが起動しない。

  • 現象

プログラムをデバッグしようとすると、「AttributeError: module 'queue' has no attribute 'Queue'」というエラーが発生する。

  • 原因

作成したプログラムのファイル名がpython標準モジュールの名前と重複している。 stackoverflow.com

  • 対策 自分の作成したプログラムの名前を変える。

リストのループが意図した通りに動かない

  • 現象 繰り返し処理する必要があるプログラムで、一度目は正常に動作するが、二度目以降は失敗する。

  • 原因

distance = map(lambda x, y:abs(x - y), data_x, data_y)

のようにmap()を使用すると、python3.xではdistanceはイテレータになる。 なので、一度読み尽してしまうとそれっきりになってしまう。

  • 対策

リスト化する

distance = list(map(lambda x, y:abs(x - y), data_x, data_y))

数列の処理が遅い

  • 現象

AOJのジャッジで、あと一歩のところで「Time Limit Exceeded」になった。少しでも処理を早くするためにリストをarrayに変更したら、かえって時間がかかるようになった。

  • 原因

不明。マージソートのプログラムで、以下のようにリストのままとarray化したもので処理速度を比較した場合、リストのままの方が速い。array化のオーバーヘッドのため?

def merge_sort(A, left, right):
    if left + 1 < right:
        mid = (left + right) // 2
        merge_sort(A, left, mid)
        merge_sort(A, mid, right)
        merge(A, left, mid, right)


def merge(A, left, mid, right):
    global Comp_count
    n1 = mid - left
    n2 = right - mid
    L = A[left:mid]
    R = A[mid:right]
    L.append(1000000001)
    R.append(1000000001)
    i = 0  # L[]用のインデックス
    j = 0  # R[]用のインデックス
    for k in range(left, right):
        Comp_count += 1
        if L[i] <= R[j]:
            A[k] = L[i]
            i += 1
        else:
            A[k] = R[j]
            j += 1


from array import array
def merge_with_array(A, left, mid, right):
    global Comp_count
    n1 = mid - left
    n2 = right - mid
    L = array('I', A[left:mid])
    R = array('I', A[mid:right])
    L.append(1000000001)
    R.append(1000000001)
    i = 0  # L[]用のインデックス
    j = 0  # R[]用のインデックス
    for k in range(left, right):
        Comp_count += 1
        if L[i] <= R[j]:
            A[k] = L[i]
            i += 1
        else:
            A[k] = R[j]
            j += 1
  • 対策

array型の方が「効率が良い」と言われているのはメモリ効率のことで、速度効率のことではない?当面は、プロファイリングしながら両方とも試してみる。

スティングしたリストから値だけを取り出したい

  • 現象

再帰関数からリストで結果を返すようにしたら、[[[2], 1, [3]], 0, [[[6], 5, [7]], 4, [8]]] のように複雑にネスティングした結果になってしまった。これを [2 1 3 0 6 5 7 4 8] のようにスッキリしたリストに整形したい。

  • 原因

再帰呼び出しを行なう関数からリストでreturnしているのがそもそもの敗因。でもせっかく作ったのでできればそのまま利用したい。

  • 対策

この手の処理は、flatten, フラット化と呼ばれている。検索するといろいろと出てくるので、処理速度、可読性、汎用性などの点からから好みの方法で処理する。 stackoverflow.com