パソコン日記

気づいたことをまとめる

Pythonでファイルの1列目を辞書(ディクショナリ)キーとして、2列目以降を値として指定する

Pythonで辞書(ディクショナリ)をうまく使いたい

pythonで辞書(ディクショナリ)はキーで値を得ることができ 、非常に便利な機能の一つです。プログラムのインプットファイル的なものを作るときに、1列目を辞書のキーとして、二列目以降をその値として読み込みたいと思ったのでプログラムを書いてみました。すぐ忘れてしまうのでメモ的な記事です。

ファイルの読み込み

次のようにファイルを読み込んでみました。

with open(inputfile, 'r') as f:
    lines = [x.strip() for x in f.readlines() if x.strip() != ""]

空白行は読み込みたくないので、最後の

if x.strip() != ""

で読み込まないようにしました。

空白で区切られたファイルの1列目をキー、2列目以降を値としてディクショナリを作成する

次のように、辞書内包表記で書いてみました。

dic = {x.split(' ', 1)[0]:x.strip().split(' ',1)[1] if len(x.split()) >= 2 else '' for x in lines}

ちょっと複雑?になってるのかもしれません。 最初の

x.split(' ',1)

は文字列xを一つ目の空白' 'で区切り、あとは区切らないという意味です。カンマで区切りたければ","で、2番目まで区切りたかったら1を2にすればいいみたいです。区切られた文字列の1番目(添字は0)をキーとし、2番目(添字は1)を値とします。 また、1列目だけ指定したいときもあると思うので

 if len(x.split()) >= 2 else ''

とし、空白などで区切られてなかったらキーのみ指定し、値に''をいれておきました。 これで意図したディクショナリを作ることができると思います。

Pythonのfloat型からint型へのキャスト(型変換)で気づいたこと

pythonでのfloat型からint型へのキャスト

pythonでfloat型からint型へキャストするときは次のようにすると思います。 今回はすべて対話型シェルで実行しました。

>>> a = 1.2
>>> int(a)
1

四捨五入されるのか切り捨てられるのか

ここで、小数点以下は四捨五入されるのか切り捨てられるのか気になりました。 次のようなキャストを行ってみました。

>>> a = 1.6
>>> int(a)
1

どうやら切り捨てられるみたいです。注意が必要ですね。

四捨五入してキャストする

使い所があるのか分かりませんが、四捨五入してキャストするには次のようにすればいいのかなと思います。

>>> a = 1.6
>>> int(round(a))

linuxでディレクトリのサイズを表示する(duコマンド)

ディレクトリ内のディレクトリやファイルの容量を表示する

du -csh ./*

これで現在のディレクトリに存在するファイルやディレクトリの容量を見やすい形で表示することができます。

duコマンド

duコマンドはディレクトリやファイルの容量を表示するコマンドです。しかし、オプションを何もつけずに実行するとサブディレクトリの容量までも表示されたり、人間にとってわかりにくい単位で表示されたりします。そこでオプションを使って見やすい形にします。

duコマンドのオプション

duコマンドには様々なオプションが準備されていますが、よく使うものをご紹介いたします。

du -c

指定したディレクトリのトータルの容量を表示することができます。

du -h

ガバイトやギガバイトなどの人間にとって見やす形式で表示してくれます。

du -s

サブディレクトリの容量を表示しません。

du -csh

これらをあわせると、指定したディレクトリ内にあるファイルやディレクトリのみの容量を表示してくれます。

bashで必要な文字列を切り出す(cat, grep, awk)

ファイルから文字列の切り出し

研究などで出力ファイルから特定の値を切り出したいときがあります。もし使っている計算機がlinuxなら次のコマンドで簡単に切り出すことができます。

cat filename | grep keyword | awk '{print $2}'

catコマンド

catコマンドは説明するまでもないと思いますが、ファイルや標準入力をそのまま標準出力に出力するコマンドです。catコマンドの出力をそのままパイプ"|"を使ってgrepコマンドに渡します。

grepコマンド

grepコマンドは文字列を検索するコマンドです。欲しい値が含まれる行を検索すれば、その行のみを得ることができます。これもパイプでawkコマンドに渡します。

awkコマンド

awkはテキストを処理するコマンドですが詳しくは省略します。先ほどのコマンドのようにprintを使うと文字列が空白で区切られ、区切られた文字列の前から順に$1、$2、$3と参照することができます。

Javaでじゃんけんゲームをつくる(switch文、while文を使う)

Javaでじゃんけんゲーム

Javaで簡単なじゃんけんをするゲームを作ってみたいと思います。また、プログラムを作る中でswitch文も使ってみます。

switch文を使ってみる

switch文とは条件に応じて処理を分ける構文です。入力された文字に対して処理を変えるプログラムを次のようにつくってみました。

import java.util.Scanner;

public class JankenGame {
    public static void main(String[] args) {
        System.out.println("手を入力してくだだい(グー:1,チョキ:2,パー:3):");
        Scanner scanner = new Scanner(System.in);
        String input = scanner.nextLine();

        switch (input) {
            case "1":
                System.out.println("グーです");
                break;
            case "2":
                System.out.println("チョキです");
                break;
            case "3":
                System.out.println("パーです");
                break;
            default:
                System.out.println("正しく入力できていません");
        }
    }
}

このプログラムではキーボードからの入力(1か2か3かその他)に応じて表示内容を変えています。このプログラムのswitch文では、"switch"に続くカッコ内の変数inputとcaseのあとに続く文字列が一致しているかどうかで実行されます。もし、"case"に続く文字列と一致していればそのcase内の文が実行され、breakによって抜けます。どれとも一致するものがなければ最後に書いてあるdefaultが実行されます。

while文でループさせてみる

次に対戦回数を入力させ、その回数分switch文をループさせてみたいと思います。ループをする方法にはfor文やwhile文があると思いますが、今回はwhile文を使って以下のようにしてみました。

import java.util.Scanner;

public class JankenGame {
    public static void main(String[] args) {

        String input;
        Scanner scanner = new Scanner(System.in);
        System.out.println("何回対戦しますか?");
        input = scanner.nextLine();
        int n = Integer.parseInt(input);

        int i = 0;
        while (i < n) {
            System.out.println("手を入力してくだだい(グー:1,チョキ:2,パー:3):");
            input = scanner.nextLine();

            switch (input) {
                case "1":
                    System.out.println("グーです");
                    break;
                case "2":
                    System.out.println("チョキです");
                    break;
                case "3":
                    System.out.println("パーです");
                    break;
                default:
                    System.out.println("正しく入力できていません");
            }
            i++;
        }
    }
}

while文ではwhileの後ろのカッコの中の条件が、真の限りループが回り続けます。

コンピュータにランダムな手を入力させる

コンピュータにランダムな手を入力させるため、まず1~3の乱数を生成します。Javaで乱数を生成するにはRandomクラスを使います

import java.util.Random;
Random rand = new Random();
int r = rand.nextInt(3) + 1

じゃんけんゲームをつくってみる

次のようにじゃんけんゲームをつくってみました。

import java.util.Scanner;
import java.util.Random;

public class JankenGame {
    public static void main(String[] args) {

        String input;
        Scanner scanner = new Scanner(System.in);
        System.out.println("何回対戦しますか?");
        input = scanner.nextLine();
        int n = Integer.parseInt(input);

        int i = 0;
        int win = 0;
        while (i < n) {
            Random rand = new Random();
            int cpu = rand.nextInt(3) + 1;

            System.out.println("手を入力してくだだい(グー:1,チョキ:2,パー:3):");
            input = scanner.nextLine();
            
            switch (input) {
                case "1":
                    if (cpu == 1) {
                        System.out.println("あいこ(あなた:グー,コンピュータ:グー)");    
                    }
                    if (cpu == 2) {
                        System.out.println("勝ち(あなた:グー,コンピュータ:チョキ)");    
                        win++;
                    }
                    if (cpu == 3) {
                        System.out.println("負け(あなた:グー,コンピュータ:パー)");    
                    }
                    break;
                case "2":
                    if (cpu == 1) {
                        System.out.println("負け(あなた:チョキ,コンピュータ:グー)");    
                    }
                    if (cpu == 2) {
                        System.out.println("あいこ(あなた:チョキ,コンピュータ:チョキ)");    
                    }
                    if (cpu == 3) {
                        System.out.println("勝ち(あなた:チョキ,コンピュータ:パー)");    
                        win++;
                    }
                    break;
                case "3":
                    if (cpu == 1) {
                        System.out.println("勝ち(あなた:パー,コンピュータ:グー)");    
                        win++;
                    }
                    if (cpu == 2) {
                        System.out.println("負け(あなた:パー,コンピュータ:チョキ)");    
                    }
                    if (cpu == 3) {
                        System.out.println("あいこ(あなた:チョキ,コンピュータ:パー)");    
                    }
                    break;
                default:
                    System.out.println("正しく入力できていません");    
                    break;
            }
            i++;
        }
        System.out.println("対戦回数" + n + "回 勝数" + win + "回"); 
    }
}

対戦回数と勝数を数えて最後に表示するようにしてみました。

C言語でバブルソートの実行時間を測る

ソートの実行時間を測る

以前の記事でプログラムの実行時間の測り方をご紹介いたしました。

1-compinfo.hatenablog.com

今回はバブルソートの実行時間を測定してみたいと思います。

バブルソートとは

バブルソート - Wikipedia

バブルソートwikipediaにあるように、ソートのアルゴリズムの一つで、隣り合う要素を比較しながらソートします。また、アルゴリズムが単純でプログラミングの学習によく用いられているそうです。

ソートの準備

バブルソートのプログラムを作る前に、ソートする配列を作らなければなりません。そこで、要素数Nのランダムな整数型の配列を生成するプログラムを作成しました。

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

int main(void) {
    int i;
    int N = 100;
    int n[N];

    srand(time(NULL));
    for(i=0; i<N; i++){
        n[i] = rand() % 10000;
    }
}

これで生成されるランダムな配列に対してソートを行ってみたいと思います。

マージソートのプログラム

マージソートのプログラムを次のように作ってみました。

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

int main(void) {
    int i,j,t;
    int N = 10;
    int n[N];

    // ランダムな配列を生成
    srand(time(NULL));
    for(i=0; i<N; i++){
        n[i] = rand() % 10000;
    }

    // 配列を表示
    printf("ソート前: ");
    for(i=0; i<N; i++){
        printf("%d ",n[i]);
    }
    printf("\n");

    // バブルソート
    for(i=0; i<N-1; i++){
        for(j=i+1; j<N; j++) {
            if(n[j] < n[i]){
                t = n[j];
                n[j] = n[i];
                n[i] = t;
            }
        }
    }

    // 配列を表示
    printf("ソート後: ");
    for(i=0; i<N; i++){
        printf("%d ",n[i]);
    }
    printf("\n");
}

とりあえず確認のため要素数Nを10で実行してみると次の結果が得られました。

ソート前: 3362 5885 7590 2004 2490 2836 6035 697 7675 5956
ソート後: 697 2004 2490 2836 3362 5885 5956 6035 7590 7675

きちんとソートされているのが確認できました。

マージソートの実行時間を測る

プログラムを次のように変更し、マージソートの実行時間を測ってみました。

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

int main(void) {
    int i,j,t;
    int N = 10000;
    int n[N];
    clock_t start, end;

    // ランダムな配列を生成
    srand(time(NULL));
    for(i=0; i<N; i++){
        n[i] = rand() % 10000;
    }

    // バブルソート
    start = clock();
    for(i=0; i<N-1; i++){
        for(j=i+1; j<N; j++) {
            if(n[j] < n[i]){
                t = n[j];
                n[j] = n[i];
                n[i] = t;
            }
        }
    }
    end = clock();

    printf("要素数: %d\n", N);
    printf("バブルソート実行時間: %f sec\n", (double)(end-start)/CLOCKS_PER_SEC);

}

これをコンパイルして実行すると、大体0.33秒あたりとなりました。この値は使っているコンピュータに依存してくると思います。 また、生成される配列は毎回異るので、実行するごとに実行時間が異なってしまいます。 要素数を増やしていくとどのような、相関があるのか気になったため、何回か実行した平均値をとって見たいと思います。 プログラムを次のようにしてみました。

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>

int main(void) {
    int i,j,k,t;
    int N = 10000; //配列の要素数
    int M = 10; //実行回数
    int n[N];
    clock_t start, end;
    double total = 0.0; //各実行時間の和
    struct timeval tv;

    for(k=0; k<M; k++){
        // ランダムな配列を生成
        gettimeofday(&tv,NULL);
        srand(tv.tv_sec * tv.tv_usec);
        for(i=0; i<N; i++){
            n[i] = rand() % 10000;
        }

        // バブルソート
        start = clock();
        for(i=0; i<N-1; i++){
            for(j=i+1; j<N; j++) {
                if(n[j] < n[i]){
                    t = n[j];
                    n[j] = n[i];
                    n[i] = t;
                }
            }
        }
        end = clock();
        total += (double)(end-start)/CLOCKS_PER_SEC;
    }

    printf("要素数: %d\n", N);
    printf("実行回数: %d\n", M);
    printf("バブルソート平均実行時間: %f sec\n", total/M);

}

ランダムな配列を生成するときに、乱数の種の生成はsrand(time(NULL))を使っていました。 しかし、これでは乱数の種は秒単位で変わるので、今回のプログラムには適していません。 そこで、更に細かい時間で乱数の種を生成できるように、上記のようにしてみました。 さらに、バブルソートの実行回数は10回としており、収束が悪いですが、時間の都合上これで行い、 有効数字を2桁でとってみます。 自分のノートパソコンでの結果は次の通りになりました。(データはかなり雑です)

配列の要素数 : 平均の実行時間(秒)
1000 : 0.0027
10000 : 0.35
100000 : 20

素数増えると実行時間結構かかりました。図でも書こうかと思いましたけどやめました。

C言語でプログラムの実行時間を測る

プログラムの実行時間を測りたい

C言語でソートのプログラムを作ってテストしたいなと思いました。 せっかく作るなら実行時間を測って、ソートのアルゴリズムの性能を評価してみたいと思います。 そこで、今回の記事ではC言語での、実行時間の測り方をまとめてみたいと思います。

clock()を使う

C言語ではプログラム実行時からの時間を取得することができるclock()があります。 実行時間を測定したいところの前でclock()を実行し、それが終了するところで再びclock()で時間を取得し それらを引けば実行時間を得ることができます。また、clock()を使うには、 time.hのヘッダファイルをインクルードする必要があります。 次にサンプルを書いてみました。

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

int main(void) {
    clock_t start, end;
    start = clock();

    int i;
    for(i = 0; i < 1000000; i++){
    }

    end = clock();
    printf("%f sec\n", (double)(end-start)/CLOCKS_PER_SEC);

}

テストなので、何もしないforループを回して時間をかけました。また、秒で表示するためにはCLOCKS_PER_SECで割る必要があります。 さらにdouble型でキャストしました。

これでアルゴリズムの処理時間が測定できそうです。