D言語入門-Hello, World

  • 問1
import std.stdio;

void main()
{
    writefln("%s, %s", "Hello", "World!");
}
  • 問2
import std.stdio;

void main(){
    writeln("Hello, World");
}
  • 問3 解答なし

変数と型

  • 問1 解答省略

  • 問2 解答なし

式と演算子

  • 問1

コンピュータでは、負の数は2の補数を用いて表されます。 2の補数の前に1の補数の説明をしましょう。

2進数における1の補数とは、各ビットの反転になります。 たとえば、8bitの300000011ですから、1の補数は11111100になります。 2の補数は、この1の補数に1を加算した値です。 すなわち、111111013の2の補数で、-3の2進数表現です。

このようにすることで、例えば3 + -3

  00000011
+ 11111101
----------
 100000000

->00000000   <- 先頭1bit(MSB)を無視した8bitは0を示す

というように、オーバーフローしてちゃんと0になります。

>>はMSBを維持しながら、シフトするので、-3 >> 111111110になります。 11111110は、10進数表現に直すとどうなるかが問題ですが、逆に1を引いてからビット反転すれば、絶対値の10進数表現になります。 つまり、11111110 - 1 => 11111101 =(flip)> 00000010となり、-2であることがわかります。

  • 問2

>>>は符号を維持しませんが、ビット表現の特性で<<はオーバーフローしない限り符号を維持し続けます。 というのは、正の数であれば、整数値はMSBから0がいくつか続いた後1がやっと出現します。 負の数であれば、MSBはからは1が幾つか続いた後0がやっと出現します。 よって、オーバーフローにならない限りは、値の符号は変わらないことがわかります。

標準入力と文字と文字列

  • 問1
import std.stdio;
import std.array;

void main()
{
    string line = readln();
    line.popFront();
    line.popFront();
    write(line);

    line = readln();
    line.popFront();
    line.popFront();
    write(line);

    line = readln();
    line.popFront();
    line.popFront();
    write(line);
}
  • 問2
%2$s - %1$x1016
  • 問3
3
3

条件分岐

  • 問1 ブロックに注意

ループ

  • 問1

インクリメントに注意

  • 問2 解答例
{
    auto index = <exprUpper>;
    auto exprLower = <exprLower>;
    for(; index > exprLower; --index){
        auto <identifier> = index - 1;
        <statement>
    }
}
  • 問3
import std.stdio;

void main()
{
    int sum;

    foreach(i; 0 .. 1000)
        if((i % 3) == 0 || (i % 5) == 0)
            sum += i;

    writeln(sum);
}
  • 問4
import std.stdio;

void main()
{
    int fib = 1;
    int fib_1 = 1;
    int fib_2 = 0;

    int sum = 0;

    while(fib < 4_000_000)
    {
        if(fib % 2 == 0)
            sum += fib;

        fib_2 = fib_1;
        fib_1 = fib;
        fib = fib_2 + fib_1;
    }

    writeln(sum);
}
  • 問5
import std.stdio;

void main()
{
    int sumPow2;
    int pow2Sum;

    foreach(i; 1 .. 101){
        sumPow2 += i;
        pow2Sum += i ^^ 2;
    }

    sumPow2 ^^= 2;
    writeln(sumPow2 - pow2Sum);
}
25164150
  • 問6
import std.stdio;

void main()
{
    int cnt;
    int sum;

    while(1){
        int n;
        readf("%s\n", &n);

        if(n < 0){
            writeln(sum / cnt);
            break;
        }else if(n < 10)
            continue;

        sum += n;
        ++cnt;
    }
}

その他の制御文

  • 問1
import std.stdio, std.string;

void main()
{
    int v1, v2;
    string op;

    readf("%s %s %s", &v1, &op, &v2);

    switch(op){
        case "+":
            writeln(v1 + v2);
            break;

        case "-":
            writeln(v1 - v2);
            break;

        case "*":
            writeln(v1 * v2);
            break;

        case "/":
            writeln(v1 / v2);
            break;

        default:
            writeln("数式がおかしいよ!");
            return;
    }
}

配列

  • 問1
import std.stdio;

void main()
{
    int[] arr = [0, 2, 4, 1, 3, 5];

    foreach(e; arr)
        writeln(e);
}
  • 問2
import std.stdio;

void main()
{
    int[] arr = [0, 2, 4, 1, 3, 5];

    foreach_reverse(e; arr)
        writeln(e);
}

又は

import std.stdio;

void main()
{
    int[] arr = [0, 2, 4, 1, 3, 5];

    for(int i = arr.length -1; i >= 0; --i)
        writeln(arr[i]);
}
  • 問3
import std.stdio;

void main()
{
    int[] arr = [0, 2, 4, 1, 3, 5];

    writefln("%([%03d]%|\n%)", arr);
}

文字列

  • 問1
import std.ascii;
import std.stdio;

void main()
{
    foreach(i; 0 .. char.max+1)
        if(isPrintable(cast(char)i))
            writefln("0x%x : %s", i, cast(char)i);
}
  • 問2
import std.conv;
import std.stdio;
import std.string;

void main()
{
    immutable num1 = readln.chomp.to!int,
              num2 = readln.chomp.to!int;

    writeln(num1 + num2);
}
  • 問3
import std.array;
import std.conv;
import std.regex;
import std.stdio;
import std.string;

void main()
{
    auto r = regex(r"(?:-|\+)?[0-9](?:[0-9],[0-9]|,[0-9]|[0-9])*(?:\.[0-9]+)?", "g");
    auto doc = readln.chomp;

    real sum = 0;

    foreach(c; doc.match(r)){
        writeln(c);
        sum += c.hit.replace(",", "").to!real;
    }

    writefln("%.3f", sum);
}

連想配列

  • 問1
import std.conv;
import std.stdio;
import std.string;

void main()
{
    auto n = readln().chomp().to!size_t();
    int[string] dict;

    foreach(unused; 0 .. n){
        string[] splitted = readln().chomp().split();
        dict[splitted[0]] = splitted[1].to!int;
    }

    foreach(name; dict.keys.sort)
        writefln("%-12s\t\t%s", name, dict[name]);
}

以下は別解

import std.algorithm;
import std.conv;
import std.stdio;
import std.string;
import std.typecons;

alias ListElem = Tuple!(string, "name",
                        int,     "value");

void main()
{
    auto n = readln().chomp().to!size_t();
    ListElem[] list;

    foreach(unused; 0 .. n){
        string[] splitted = readln().chomp().split();
        list ~= ListElem(splitted[0], splitted[1].to!int());
    }

    foreach(e; list.sort!"a[0] < b[0]"())
        writefln("%-12s\t\t%s", e[0], e[1]);
}
  • 問2
import std.conv;
import std.stdio;
import std.string;

void main()
{
    auto n = readln().chomp().to!size_t();
    string[][int] dict;

    foreach(unused; 0 .. n){
        string[] splitted = readln().chomp().split();
        dict[splitted[1].to!int] ~= splitted[0];
    }

    foreach(value; dict.keys.sort){
        foreach(name; dict[value].sort)
            writefln("%-12s\t\t%s", name, value);
    }
}

以下は別解

import std.algorithm;
import std.conv;
import std.stdio;
import std.string;
import std.typecons;

alias ListElem = Tuple!(string, "name",
                        int,     "value");

void main()
{
    auto n = readln().chomp().to!size_t();
    ListElem[] list;

    foreach(unused; 0 .. n){
        string[] splitted = readln().chomp().split();
        list ~= ListElem(splitted[0], splitted[1].to!int());
    }

    list.multiSort!("a[1] < b[1]", "a[0] < b[0]")();
    foreach(e; list)
        writefln("%-12s\t\t%s", e[0], e[1]);
}

関数

import std.conv, std.stdio, std.string;

int readInt()
{
    return readln().chomp().to!int();
}
int sum(int[] arr) pure nothrow @safe
{
    int s;

    foreach(e; arr)
        s += e;

    return s;
}

もし、std.algorithm.reduceを使うなら、以下のようになります。

import std.algorithm;

int sum(int[] arr) pure nothrow @safe
{
    return reduce!"a + b"(0, arr);
}

return 0;など、適当な値を返すよりも、assert(0);を入れておく方が良いプログラムになります。

import std.stdio;

int g1 = 1,
    g2 = 10,
    g3 = 20;


int getGlobalValue(size_t idx) nothrow @safe
{
    switch(idx){
        case 1:
            return g1;

        case 2:
            return g2;

        case 3:
            return g3;

        default:
    }

    assert(0);
}


void main()
{
    writeln(getGlobalValue(1));
    writeln(getGlobalValue(10));
    writeln(getGlobalValue(20));
}

return;main関数を終わらせれば良い。

import std.getopt;
import std.stdio;


immutable appInfo = `example:
$ add --a=12 --b=13
a + b = 25

$ add --b=1, --a=3
a + b = 4`;


void main(string[] args) @safe
{
    int a, b;
    bool h_sw;              // argsに-h, --helpが出現したかどうか

    getopt(args,
        "a", &a,
        "b", &b,
        "h|help", &h_sw);

    if(h_sw){
        writeln(appInfo);
        return;
    }

    writeln("a + b = ", a + b);
}
int gt(int a, bool b = false) nothrow @safe
{
    static int sum;

    if(b)
        sum = 0;

    sum += a;
    return sum;
}
int taggedGt(string tag, int a, bool clear = false, bool delete_ = false) nothrow @safe
{
    static int[string] sum;

    if(clear)
        sum[tag] = 0;

    if(delete_){
        sum.remove(tag);
        return a;
    }else{
        sum[tag] += a;
        return sum[tag];
    }
}
auto createCounter() pure nothrow @safe
{
    size_t a;

    size_t counter(){
        return ++a;
    }

    return &counter;
}

もし、ラムダを使うなら次のほうが短い。

auto createCounter() pure nothrow @safe
{
    size_t a;

    return () => ++a;
}

1.

import std.algorithm;

int sumOfEven(int[] arr) pure nothrow @safe
{
    return reduce!"a + b"(0, arr.filter!"!(a&1)"());
}

2.

import std.algorithm;
import std.math;

int getApprxEqElm(int[] arr, int needle) pure @safe
{
    int f(int a, int b) nothrow @safe
    {
        int diffA = abs(a - needle),
            diffB = abs(b - needle);

        return diffA > diffB ? b : a;
    }

    return reduce!f(arr);
}

メイン関数

ファイルと標準入出力

  • 問1
import std.range,
       std.stdio;

void main()
{
    foreach(i; 0 .. 3){
        auto line = readln();

        // もしくはline.popFrontN(2);
        foreach(j; 0 .. 2)
            line.popFront();

        write(line);
    }
}

もしくは、std.range.dropを使って以下のように書けます。

import std.range,
       std.stdio;

void main()
{
    foreach(_; 0 .. 3)
        readln().drop(2).write();
}
  • 問2

1.

import std.file;

void copyTo(string from, string to)
{
    to.write(from.read());
}

2.

void copyTo(string from, string to)
{
    auto fromFile = File(from);
    auto toFile = File(to, "w");

    foreach(buf; fromFile.byChunk(4096))
        toFile.rawWrite(buf);
}
  • 問3
import std.conv,
       std.stdio,
       std.string;

void main()
{
    immutable filename = readln().chomp(),
              N = readln().chomp().to!int();

    auto file = File(filename, "w");

    foreach(i; 0 .. N)
        file.write(readln());
}