secretbase.log

.NET/C#/Pythonなど

Python の辞書に含まれる最大値のKeyを求めるクールな実装

下記のような辞書型があり、辞書の値の最大値を持つキーを取得したい。
例えば、下記のような辞書だ。

d = {'a': 1, 'b': 2, 'c': 3}

上記例では、 3 が最大値。よって、 c を得たい。
ここで if文のような条件分岐をつかった実装は クールではないのは容易に想像がつく。

ちなみに、最大値は、組み込み関数の max で取得できる。

>>> max(d.values())
3

とやると、3 を取得することはできるが、そのキーはどうすれば取得できるだろう。

Python ではどのような実装がクールなのだろうか、とつぶやいたら RT され 一瞬で Reply をいくつかいただけた。
ありがたく、ご紹介させて頂く。
(一応、Python 2.7.5 を想定したのだが、明示しなかったので py3向けの回答もあったのかもしれない)


1. タプルにして最大値を求める実装

>>> max([(v,k) for k,v in d.items()])[1]
'c'
>>> max((v,k) for (k,v) in d.items())[1]
'c'

d.items() でタプルのペアを含むリストが取得できる。

>>> d.items()
[('a', 1), ('c', 3), ('b', 2)]

最初の例は、リスト内包表記を用いリストにしそれを渡している。
2番目の例は、引数として複数のタプルを渡している。

いずれの例も、for文で内部のタプルを取り出し v (value)の最大値を求める。
最後の [1] を k を意味している。

max の仕様として、リスト(のようなiteratable)または複数の引数を受け付けるという仕様。Docstring を読む。

max(iterable[, key=func]) -> value
max(a, b, c, ...[, key=func]) -> value

なお、Python 2系なら items の変わりに iteritems を使うと気持ち効率が良いらしい(未確認)




2. max のオプション引数 key を用いる実装 (itemgetter)

>>> from operator import itemgetter
>>> max(d.items(), key=itemgetter(1))[0]
'c'

ここで maxの仕様 に目を通すと以下のような記載がある。

オプションの key 引数には list.sort() で使われるのと同じような 1 引数の順序付け関数を指定します。

Python 2.5以降で使える。 key= で関数を渡す。これを用いた実装だ。ここでは itemgetter() を使っている。

operator モジュールで提供されている。

>>> itemgetter(1)(("c",3))
>>> 3

ここでは、上記のように 1番目のタプルの要素を渡す関数となっている。



3. max のオプション引数 key を用いる実装 (lambda)

>>> max(d.items(), key=lambda x:x[1])[0]
'c'

lambdaを用い 配列要素の1番目を返却する無名関数を作成し、オプション引数に渡す実装。
これが一番シンプルな実装な気もする。



WPF MVVM ふりかえり 発表資料

今年度から C#/WPF/MVVM/Prism な開発環境で過ごすことが多くなって来ました。私は実際の開発よりもCIやインストーラなどの役回りなのですが勉強しないといけないと思い、今日の mokusharp(木曜日 社内C#勉強会)で発表した資料になります。

発表資料(前編)

WPFとはなに? XAMLとは?MVVMとはと聞かれたときにいまいちイメージがつかめていなかったので、インターネットで参考になった有益な情報をまとめたガイドのような感じです。あくまで概要でざっと理解するためには役立つかと思います。

後編は?

後編としては、データバインディング、データテンプレート、コマンド、ビヘイビア を理解できる発表資料を行う予定です。

ackより速いagを試してみる

ackより速いらしいagを試してみました。ackはgrepをよりプログラマ向けに便利にしたもので、agはperlで記述されたackよりCで書いている分高速であることがウリとのことです。

インストール

debian GNU/Linux 7.0 wheezy 上で行います。Ubuntuでも同じ手順でインストールできます。

準備

$ sudo aptitude install automake pkg-config libpcre3-dev zlib1g-dev liblzma-dev

ビルド

$ git clone git://github.com/ggreer/the_silver_searcher.git
$ cd the_silver_searcher
$ ./build.sh
$ sudo make install

比較

バージョン

ack-grep 1.96
ag 0.15pre

Mercurialソースコードで ctx を検索してみます。

~/work/hg $ time ack-grep ctx

...

real    0m1.405s
user    0m0.448s
sys     0m0.100s
~/work/hg $ time ag ctx

...

real    0m0.274s
user    0m0.064s
sys     0m0.036s

この結果では、ag は、5倍くらい速い結果が得られました。

SSH キーをクリップボードにコピーするワンライナー

あらかじめ、 ssh-keygen でキーを作成しましょう。

公開鍵をコピーしたくなったときに、下記コマンドを実行します。

$ xclip -sel clip < ~/.ssh/id_rsa.pub

Ctrl + V で貼り付けることができます。


インストール

debian の場合、 xclip は、下記コマンドでインストール可能です。

$ sudo aptitude install xclip

debian 7 の Sphinx にて Could not import extension となる問題の原因と対策

debian 6 から 7.0 に upgrade したところ、sphinx の make html でエラーが出るようになってしまった。

Extension error

Extension error:
Could not import extension sphinxcontrib.plantuml (exception: No module named plantuml)
make: *** [html] エラー 1


調べてみると debian の pkg でインストールした場合に発生する現象である。
真の原因は果たしてなんであろうか、気になったので再現用のリポジトリを用意しました。
なお、ここでエラーとなっている extension はリポジトリ内に含めています。


正常時のログとエラーログ

https://gist.github.com/cointoss1973/268cb91ee21a4fb352ca

sys.path の環境変数の違いがなにか影響しているかと思われるが、果たして..




原因と対策

追記 2013/05/10

debiansphinx パッケージにパッチがあたっており、 sphinxcontrib の名前がぶつかっているようです。 リポジトリ内の sphinxcontrib の名前を変えることで回避できそうですね。さてどんな名前にしようか...

ifconfig コマンドの導入

debian GNU/Linux 7.0 への ifconfig インストール方法のメモ。

インストール方法

$ sudo aptitude install net-tools

実行方法

/sbin なので通常のユーザではPATHが通っていないことに注意。

$ /sbin/ifconfig

インストールパスの確認方法

$ dpkg -L net-tools | grep ifconfig
...
...
/sbin/ifconfig

local time から始めるプログラミング言語入門

プログラミング入門としては、Hello World を標準出力に出力することがよくあります。初めて触る言語で行うサンプルとして、Hello World より少しだけ進んで local time の現在時刻を表示するサンプルコードをいくつかつくってみました。
[2013/01/24 12:34:56] という現在時刻をメッセージやログに日付付きで記録したいときに役立つフォーマットです。

扱うプログラミング言語は、TIOBE で上位にランクされる人気の言語から C Java C++ C# Python Perl JavaScript Ruby とあと いくつかのプログラミング言語や環境で試してみます。

環境としては、主にWindows上で、いくつかMSYSで行なっています*1


C による実装

clock_gettime() を用います。time.h を include することで使用可能です。

#include <stdio.h>
#include <time.h>

#define TIME_MAXSIZE 64

void nowtime(char *str)
{
	time_t timer = time(NULL);
	strftime(str, TIME_MAXSIZE, "[%Y/%m/%d %H:%M:%S]", localtime(&timer));
}

int main()
{
	char timestr[TIME_MAXSIZE];
	
	nowtime(timestr);
	printf("%s\n", timestr);

	return 0;
}

$ gcc -Wall time.c;./a
[2013/02/05 20:38:41]





Java による実装

Date 型で取得する関数 Date()があり、SimpleDateFormatクラスのformatメソッドで指定したString型に変換可能です。

import java.util.*;
import java.text.*;

public class NowTime {
	public static void main(String[] args){
		System.out.println(getNowTime());
	}
	static String getNowTime(){
		Date now = new Date();
		SimpleDateFormat fmt = new SimpleDateFormat("[YYYY/MM/dd HH:mm:ss]");
		return fmt.format(now);
	}
}

$ javac NowTime.java ; java NowTime
[2013/02/08 19:36:16]




C++ による実装

boost を用いてみたいと思います。ですが私の頭では Date_Time の仕様がよく理解できず、stackoverflow の回答をおもいっきり参考にさせて頂きました。
http://stackoverflow.com/questions/1904317/c-boost-date-with-format-dd-mm-yyyy

#include <iostream>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/posix_time/posix_time_io.hpp>

using namespace boost::posix_time;
using namespace std;

void nowtime(void)
{
	time_facet *facet = new time_facet("[%Y/%m/%d %H:%M:%S]");
	cout.imbue(locale(cout.getloc(), facet));
	cout << second_clock::local_time() << endl;
}

#ifdef DEBUG
int main(int argc, char **argv)
{
	nowtime();
}
#endif

$ g++ -Wall -I/usr/include/boost -DDEBUG nowtime.cpp ;./a
[2013/02/16 23:16:32]





C# による実装

DateTimeオブジェクトを取得し ToString で文字列に変換します。

using System;

class Datetime
{
	public static void Main()
	{
		Console.WriteLine(DateTime.Now.ToString("[yyyy/MM/dd HH:mm:ss]"));			
	}
}

Visual Studio コマンドプロンプトを開くことで、csc.exe(コンパイラ)にパスが通ります。

> csc nowtime.cs にてコンパイルを行いましょう。
> nowtime
[2013/02/23 22:28:45]




Python による実装

標準ライブラリ datetime が使いやすいです。import しましょう。

import datetime

print datetime.datetime.today().strftime('[%Y/%m/%d %H:%M:%S]')

python nowtime.py
[2013/01/24 21:25:11]




Perl による実装

localtime 関数にて現在の時刻を示す9個の時刻情報が返却されますので、書式を整えましょう。

#!/usr/bin/perl

sub nowtime {
	my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);

	my $date = sprintf("[%04d/%02d/%02d %02d:%02d:%02d]\n", 
					   $year+1900,$mon+1,$mday,$hour,$min,$sec);
	return $date;
}

print nowtime();

$ perl nowtime.pl
[2013/02/17 00:41:47]




JavaScript による実装

Dateオブジェクトにて現在時刻が取得できます。

var today = new Date();

var fmt = "["+ today.getFullYear()+"/"+today.getMonth()+1
        +"/"+today.getDay()+" "
        +today.getHours()+":"+today.getMinutes()+":"+today.getSeconds()+"]"

WScript.echo(fmt);

Windows 上で explorer nowtime.js という形で起動します(またはnowtime.js ファイル)をダブルクリックします。



Ruby による実装

#!/usr/bin/env ruby

def nowtime
  return Time.now.strftime("[%Y-%m-%d %H:%M:%S]")
end

puts nowtime

$ ruby nowtime.rb
[2013-02-17 01:36:04]



bash による実装

date コマンド(GNU date) に頼ることにします。

echo "["`date +"%Y/%m/%d %k:%M:%S"`"]"

[2013/01/24 20:24:25]




コマンドプロンプト(Windowsバッチファイル)による実装

echo [%date% %time:~,-3%]

[2013/04/08 22:30:52]




Windows Power Shell による実装

Get-Date コマンドレットを使用します。

PS C:\> Get-Date -format ["yyyy/MM/dd hh:mm:ss"]

[2013/04/09 12:13:36]





Emacs Lisp による実装

M-x にて ielm にてインタラクティブシェルを起動します。
(スクラッチバッファにて C-j でも実行することができます)

ELISP> (format-time-string "[%Y/%m/%d %H:%M:%S]" (current-time))
"[2013/03/01 10:50:44]"

さいごに

表示された日付時刻がまちまちなのは、それぞれのプログラミング言語で実装した時刻の差です。いろいろな言語を気長に試した結果なので気にしないでくださいね。



追記。その他いくつかの言語による実装を行われた方がいましたのでリンクをご紹介します。

*1:C,C++perlbashはMSYSで行いました。