ぷろみん

プログラミング的な内容を扱ってます

mapよりもunordered_mapを使おう

unorderedとは

要するにハッシュです。検索が早くなるので基本的にはunordered_mapを使いましょう。
mapはorderedつまり常にソートされた状態で保持されますが、これが有効に働くことは連想配列的な使い方ではまず無いでしょう。

でもkeyに複雑な値が来る場合は辛い

unordered_mapではkey値からハッシュ値が計算できないと機能しません。
その為、key値に複雑な型が来る場合はハッシュの計算仕方を教えてあげなければいけません。

#include<iostream>
#include<unordered_map>
#include<functional>

namespace torini{
    struct Key{
        int value = 0;
        
        // keyは等号を処理できなければ同じか判断できません
        bool operator==(const Key& other) const{
            return value == other.value;
        }
    };
    struct Hash{
        std::size_t operator()(const Key& key) const{
            // ここに良い感じのハッシュ関数を書きましょう
            return 0;
        }
    };
    using Map = std::unordered_map<Key, int, Hash>;
}

int main(){
    torini::Map map;
    // map.insert(std::make_pair(torini::Key(), 1));よりもオススメ
    map.emplace(torini::Key(), 1);

    // 1が出力される
    std::cout << map.find(torini::Key())->second;
}

妥協策

定義されてあるようなプリミティブな型はunordered_mapを使い、他はmapを使う。 mapで速度的な負担が計測されたらHashを書く。で良いんじゃないですかね!

探して見つかった場合と見つからなかった場合の処理

C++14の機能を利用しているのでコンパイラによってはビルドが通らないです。

ありがち

処理の分割がいまいちで、コードを読む時に分かりにくいです。
また、for内で読み込みと書き込みを同時に行っているのは良くない書き方の兆候です。

#include<vector>
#include<utility>

int main(){
    std::vector<std::pair<bool, int>> v;
    // スコープが長いフラグ変数は怖い
    bool find = false;
    for(auto &&item: v){
        if(item.first){
            // ここでうっかり要素の追加とかすると危険な可能性がある
            item.second = 5;
            find = true;
            break;
        }
    }
    
    if(find){
        // ...
    } else {
        // ...
    }
}

標準ライブラリ

こういう処理はfind_ifを使うと良い感じに書けます。

#include<vector>
#include<utility>
#include<algorithm>

int main(){
    std::vector<std::pair<bool, int>> v;
    auto result = std::find_if(v.begin(), v.end(), [](const auto &item){
        return item.first;
    });
    
    // ちょっとここがダサい
    if(result != v.end()){
        result->second = 5;
        // ...
    } else {
        // ...
    }
}

linq的なアプローチ

何となく意図が掴めれば良いという感じで書いたコードなのでちゃんと動きません。

しっかりとしたlinq的な挙動が良いのならcpplinqを参照してください。
LINQ for C++ - Home

要するに対象を絞った後で処理をするテンプレートの様なものです。

このままだと上手く代入できません。
この辺の問題でしょうか?どちらにしろ理解不足です。
c++ - std::optional specialization for reference types - Stack Overflow

#include<vector>
#include<utility>
#include<experimental/optional>

template<class Container, class Func>
auto Where(Container &v, Func func)
// optionalにはautoが効かない。ぐぬぬ
-> std::experimental::optional<typename Container::value_type>
{
    for(auto &&item: v){
        if(func(item)){
            return item;
        }
    }
    return std::experimental::nullopt;
}

int main(){
    std::vector<std::pair<bool, int>> v;
    auto target = Where(v, [](auto&& item){ return item.first; });
    
    if(target){
        // ここでの代入が上手く機能しないのでもう少し考える必要がある
        (*target).second = 5;
        // ...
    } else {
        // ...
    }
}

javascript style guide

方針

知識のある人は既にコードレベルの情報は発信しません。
望むのは正しいコードの書き方なので、それを引き続き探します。
前回の方針とは少し方向を変えて集合知に頼ってみます。

wikipedia

やはり困ったらwikipediawikipediaは良いのですが、ページが細分化されている上英語じゃないと情報が少ない事が多いので案外盲点だったりします。

JavaScript syntax - Wikipedia, the free encyclopedia

github

コードや実装で困ったらgithubですが、なかなか丁度良いものは無いものです。
今回は幸運にもベストなのがありました。

github.com

日本語版もあるので、必要に応じて参照するのが良さそうです。

javascriptの情報を拾う場所

javascriptをちゃんと学習する気になったのでメモ

方針

最新の規格等に触れているブログ等を主軸に探します。
javascript draft等で検索

文法

ECMAScript Syntax Grammar 6th Edition / Draft

ECMAScript Language Specification ECMA-262 6th Edition – DRAFT

ブログとか人とか

  • azuさん

JSer.info

Web Scratch

  • teramakoさん

hogehoge @teramako

感想

javascriptの文法とか規格とかに言及している人はあまりみかけないなーといった印象です。
やはり外部のライブラリやサービスありきの言語なのでしょうか。 ひとまず文法を理解してからライブラリも徐々に拾っていきたいです。

ninjaのwindows環境ビルド

環境

windows8.1, visual studio community, python2.7

準備

PATHに追加

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\bin
C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\Tools

INCLUDEに追加

C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\INCLUDE
C:\Program Files (x86)\Windows Kits\8.1\Include\um
C:\Program Files (x86)\Windows Kits\8.1\Include\shared

LIBに追加

C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\x86 or x64 or arm
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\lib

実行

git clone git://github.com/martine/ninja.git ninja
cd ninja
python configure.py --bootstrap

ninja.exeができているはずです。

関数ポインタよりもstd::functionを使おう

書きやすさ

// 関数ポインタ
void (*Func)(void);
void (Foo::*Func2)(void);

// std::function
std::function<void(void)> Func;
std::function<void(Foo*)> Func2;

これは慣れてないと両方読みづらいかもしれませんね。
慣れるとfunctionの方が型名、変数名といういつものルールに従っているので分かりやすくなります。

運搬性

void Test(){}
// 関数ポインタ
using ReturnFunction = void (*)();
ReturnFunction Func(){
    return Test;
}
// C++14から以下の書き方もできる
auto Func(){
    return Test;
}

// std::function
std::function<void()> Func(){
    return Test;
}

戻り値に関数ポインタを使う場合にはusingかtypedef宣言が必要になります。
autoを使えば省略できますが以下の事に注意する必要があります。

auto Func(){
    return Test;
}

void Func2(ReturnFunction a){}
void Func2(std::function<void()> a){}

int main(){
    auto a = Func();
    // 関数ポインタ版の方が優先して呼ばれる
    Func2(a);
}

部分適用

これは関数ポインタでは実現できないと思います。

void Int3(int, int, int){}

int main(){
    std::function<void(int, int, int)> a = Int3;
    // 3番目の引数を3で固定した引数が2個の関数を生成する
    std::function<void(int, int)> b = std::bind(a, std::placeholders::_1, std::placeholders::_2, 3);
}

この機能はメンバ関数ポインタと合わせると更に強力で、メンバ関数インスタンスを拘束して通常の関数の様に扱ったりできます。

class Foo{
public:
    void FooFunc(){}
};

int main(){
    Foo foo;
    std::function<void()> Func = std::bind(&Foo::FooFunc, &foo);
    // メンバ関数を通常の関数として呼べる
    Func();
}

初期値

// 関数ポインタ
ReturnFunction a = nullptr;
if(a != nullptr){
    a();
}

// std::function
// 明示的初期化必要無し
std::function<void()> a;
// operator boolが設定してあるのでチェックも容易
if(a){
    a();
}

ラムダ

std::functionならラムダの運搬も可能です。

std::function<void(void)> a = []{};

ただし、キャプチャにローカルオブジェクトを含む場合不定値になるので注意が必要です。