ページ 11

基本型以外のlistのsortについて

Posted: 2009年11月18日(水) 23:44
by 山崎
いつもお世話になっております、山崎です。
今回は、基本型以外の型のlistをsortする際について伺いに参りました。

現在、アクションゲームを製作しています。
フィールドに配置するオブジェクトを格納するlistを修正しているのですが、
このlistには、描画する順番にオブジェクトが格納されているようにしたいと思っています。
このオブジェクトを表すクラスObjectはshort型のメンバYを持っているのですが、
listにはこのYの小さい順にオブジェクトを格納しておきたいと思っています。

各オブジェクトが位置を変えた後やlistに新しいオブジェクトを追加した後などに、
Yの小さい順にlistをソートしようと思っています。

そこで、listには要素をソートする関数sortがあると思い出し、
早速それを使ってみようと思ったのですが、
どうすればYの昇順にソートさせるという指定ができるのかわかりません。
いつも参考にしているサイトには、int型のlistのsortは載っていたのですが・・・。

どうすれば、自分で作ったクラスのあるメンバの大小に従ったlistのsortを行えるのでしょうか。

Re:基本型以外のlistのsortについて

Posted: 2009年11月19日(木) 01:27
by ドラ
sort()には関数オブジェクトを引数にとるバージョンが存在するのでそれを使います。
文章で説明し辛かったので簡単なサンプルを作ってみました。
赤字の部分が今回の質問に関係する部分です。
#include <iostream>
#include <iomanip>
#include <list>
#include <algorithm>
#include <iterator>
#include <functional>
#include <cstdlib>
#include <ctime>

class Object
{
public:
	Object(short x, short y) : X(x), Y(y) {}
	short getX() const { return X; }
	short getY() const { return Y; }
private:
	short X;
	short Y;
};

std::ostream& operator<<(std::ostream& os, const Object& obj)
{
	return os << "X = " << std::setw(3) << obj.getX()
			  << ", Y = " << std::setw(3) << obj.getY();
}

struct LessY : std::binary_function<Object, Object, bool>
{
	bool operator()(const Object& a, const Object& b) const
	{
		return a.getY() < b.getY();
	}
};

int main()
{
	std::srand(static_cast<unsigned int>(std::time(0)));
	
	std::ostream_iterator<Object> out(std::cout, "\n");
	std::list<Object> lst;
	
	for (int i = 0; i != 10; ++i)
	{
		lst.push_back(Object(std::rand()%100, std::rand()%100));
	}
	
	std::cout << "ソート前\n";
	std::copy(lst.begin(), lst.end(), out);
	std::cout << std::endl;
	
	std::cout << "ソート後\n";
	lst.sort( LessY() );
	std::copy(lst.begin(), lst.end(), out);
	std::cout << std::endl;
	
	return 0;
}

Re:基本型以外のlistのsortについて

Posted: 2009年11月19日(木) 12:02
by 山崎
ドラさん
ご返信誠にありがとうございます。
わざわざサンプルまで示してくださり、恐縮です。

おかげで、Objectのlistをsortするプログラムができました。
本当にありがとうございました。



サンプルコードを見て、私なりに解釈して小さなプログラムを作ってみたのですが、
正しく理解できているかどうかまだ少し懸念がありまして…。
以下に私の作ったObjectのlistをsortするプログラムを載せますので、
よろしければ、おかしいところがあればどなたか指摘頂けないでしょうか。
私の解釈をコードにコメントとして載せてあります。

listのsortはうまく行きましたので「解決!」にさせて頂きますが、
ご指摘くださる方がいらっしゃれば幸いです。
#include <iostream>
#include <list>
#include <stdlib.h>
#include <functional>//このプログラムでは使用していない?
using namespace std;

class Object
{
public:
	short X;
	short Y;

	Object()
	{
		X=rand();//short型に代入するべきではないかも
		Y=rand();
	}
};

//ドラさんのサンプルコードではstructだったが、classでも可能だろうか
class FunctionObject
{
public:
	//bool型を返し、二つのObjectを引数とした、operator()を定義しなければいけない、という解釈
	bool operator()(const Object* Obj1,const Object* Obj2)
	{
		return (Obj1->Y < Obj2->Y);
	}
};

int main()
{
	list<Object*> ObjectList;

	cout << "ソート前" << endl;
	for(int i=0;i<10;i++)
	{
		Object* ObjTemp=new Object();
		ObjectList.push_back(ObjTemp);
		cout << ObjTemp->Y <<endl;
	}

	//関数オブジェクトのクラス名に()をつけたものを、sortの引数にすればいいという解釈
	ObjectList.sort(FunctionObject());

	cout << "ソート後" << endl;
	list<Object*>::iterator it=ObjectList.begin();
	while(it != ObjectList.end())
	{
		cout << (*it)->Y <<endl;
		++it;
	}

	return 0;
}

Re:基本型以外のlistのsortについて

Posted: 2009年11月19日(木) 21:52
by ドラ
>#include <functional>//このプログラムでは使用していない?
使用していません。
関数オブジェクトを関数アダプタと組み合わせて使う場合に必要な型情報をくっつけるために
std::binary_functionからpublic継承させたので #include <functional> が必要でした。
関数アダプタと組み合わせて使わない事が分かっていれば必要ないと思います。


>//ドラさんのサンプルコードではstructだったが、classでも可能だろうか
可能です。
C++のstructとclassはデフォルトのアクセスラベルとデフォルトの継承タイプが異なるだけです。


>//bool型を返し、二つのObjectを引数とした、operator()を定義しなければいけない、という解釈
その解釈であっています。


>//関数オブジェクトのクラス名に()をつけたものを、sortの引数にすればいいという解釈
>ObjectList.sort(FunctionObject());
FunctionObjectクラスの一時オブジェクトを作って、それを引数として渡しています。

Re:基本型以外のlistのsortについて

Posted: 2009年11月20日(金) 01:45
by 山崎
ドラさん
ご返信誠にありがとうございます。

私のプログラムを見ていただき、本当にありがとうございます。
おかげで、教えて頂いたコードをきちんと理解することができました。
感謝の言葉もございません!!

いろいろ教え頂きありがとうございました。