3
0

More than 3 years have passed since last update.

【C++/OpenSiv3D】Array::remove_if() の使い方

Posted at

OpenSiv3D では std::vector の代わりに Array を使います。Array にはさまざまな便利なメンバ関数が用意されていますが、その中でも知っていると便利な Array::remove_if(f) の使い方を紹介します。

Array::remove_if(f) は、Array の個々の要素 x に対して f(x) == true となる要素を Array から削除します。C++ 標準ライブラリの v.erase(std::remove_if(v.begin(), v.end(), f), v.end()) と同じ働きです。

例 1

Array<int32> から、10 未満の要素を削除する。

# include <Siv3D.hpp>

void Main()
{
    Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };

    Print << v;

    v.remove_if([](int32 n){ return n < 10; });

    Print << v;

    while (System::Update())
    {

    }
}
{3, 9, 10, 12, 8, 6, 11}
{10, 12, 11}

▼ 上級者向けのテクニックですが、OpenSiv3D の LessThan オブジェクトを使ってこのようにも書けます。

# include <Siv3D.hpp>

void Main()
{
    Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };

    Print << v;

    v.remove_if(LessThan(10));

    Print << v;

    while (System::Update())
    {

    }
}
{3, 9, 10, 12, 8, 6, 11}
{10, 12, 11}

例 2

Array<int32> から偶数を削除する。

# include <Siv3D.hpp>

void Main()
{
    Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };

    Print << v;

    v.remove_if([](int32 n){ return n % 2 == 0; });

    Print << v;

    while (System::Update())
    {

    }
}
{3, 9, 10, 12, 8, 6, 11}
{3, 9, 11}

▼ 要素と同じ型の値を引数に取り bool を返すような関数があれば、それを使うこともできます。
IsEven(x) は整数 x が偶数なら true, そうでなければ false を返す関数で、 OpenSiv3D に実装されています。

# include <Siv3D.hpp>

void Main()
{
    Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };

    Print << v;

    v.remove_if(IsEven);

    Print << v;

    while (System::Update())
    {

    }
}
{3, 9, 10, 12, 8, 6, 11}
{3, 9, 11}

例 3

Array<Vec2> で表される点群から、指定した Rect 上にある点を削除する。

# include <Siv3D.hpp>

void Main()
{
    Array<Vec2> points;

    for (int32 i = 0; i < 300; ++i)
    {
        points << RandomVec2(Scene::Rect());
    }

    constexpr Rect rect(200, 200, 400, 200);

    // [rect] で rect をコピーキャプチャし、ラムダ式の中で使えるようにする
    points.remove_if([rect](const Vec2& point){ return point.intersects(rect); });

    while (System::Update())
    {
        rect.drawFrame(1, 0, ColorF(0.3));

        for (const auto& point : points)
        {
            Circle(point, 4).draw();
        }
    }
}

例 4

モンスターの配列 Array<Monster> (Monster はユーザが作ったクラス) から、残り寿命が尽きたモンスター (Monster::isAlive()false を返す) を削除する。

# include <Siv3D.hpp>

class Monster
{
private:

    // 位置
    Vec2 m_pos;

    // 残り寿命(秒)
    double m_lifeTimeSec = 0.0;

public:

    Monster() = default;

    Monster(const Vec2& pos, double lifeTimeSec)
        : m_pos(pos)
        , m_lifeTimeSec(lifeTimeSec) {}

    // モンスターの更新(残り寿命を減らす)
    void update(double timeDeltaSec)
    {
        m_lifeTimeSec -= timeDeltaSec;
    }

    const Vec2& getPos() const
    {
        return m_pos;
    }

    // まだ残り寿命があれば true
    bool isAlive() const
    {
        return (m_lifeTimeSec > 0.0);
    }
};

void Main()
{
    // モンスター描画用の絵文字
    const Texture monsterTexture(Emoji(U"👾"));

    Array<Monster> monsters;

    for (int32 i = 0; i < 30; ++i)
    {
        // 画面上のランダムな場所にランダムな寿命のモンスターを作成
        monsters << Monster(RandomVec2(Scene::Rect()), Random(1.0, 8.0));
    }

    while (System::Update())
    {
        // 前のフレームからの経過時間
        const double timeDeltaSec = Scene::DeltaTime();

        for (auto& monster : monsters)
        {
            monster.update(timeDeltaSec);
        }

        // 寿命が尽きたモンスターを Array から削除
        monsters.remove_if([](const Monster& m){ return !m.isAlive(); });

        // モンスターを描画
        for (const auto& monster : monsters)
        {
            monsterTexture.scaled(0.5).drawAt(monster.getPos());
        }
    }
}

似た名前の関数に注意

Array::removed_if(f) という関数もありますが、これは削除した結果の新しい Array を返す関数で、自分自身は変更しません。

# include <Siv3D.hpp>

void Main()
{
    Array<int32> v = { 3, 9, 10, 12, 8, 6, 11 };

    Print << v.removed_if(IsEven);

    Print << v;

    while (System::Update())
    {

    }
}
{3, 9, 11}
{3, 9, 10, 12, 8, 6, 11}
3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0