Javaを使うなら理解しておきたいアルゴリズム - 抽出・ソート・結合・集計 (リスト&ビーン編)

Javaでのリスト&ビーンを使用したアルゴリズムの書き方の覚書です。

説明に使用するデータ構造

アルゴリズムの説明のために、以下のようなビーンのリストを使います。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////

/**
 * 国データ
 */
class Country {
	private String name;		// 名前
	private String currency;	// 通貨
	private Integer population;	// 人口
	
	public void setName( String name ) {
		this.name = name;
	}
	
	public String getName() {
		return name;
	}
	
	public void setCurrency( String currency ) {
		this.currency = currency;
	}
	
	public String getCurrency() {
		return currency;
	}
	
	public void setPopulation( Integer population ) {
		this.population = population;
	}
	
	public Integer getPopulation() {
		return population;
	}
}

//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////

List countries = new ArrayList();

Country country;

country = new Country();
country.setName( "日本" );
country.setCurrency(   "JPY" );
country.setPopulation( 127156000 );
countries.add( country );

country = new Country();
country.setName( "フランス" );
country.setCurrency( "EUR" );
country.setPopulation( 65073482 );
countries.add( country );

country = new Country();
country.setName( "スペイン" );
country.setCurrency( "EUR" );
country.setPopulation( 44904000 );
countries.add( country );

country = new Country();
country.setName( "ロシア" );
country.setCurrency( "RUB" );
country.setPopulation( 141903979 );
countries.add( country );

country = new Country();
country.setName( "ベトナム" );
country.setCurrency( "VND" );
country.setPopulation( 84238000 );
countries.add( country );

country = new Country();
country.setName( "カンボジア" );
country.setCurrency( "KHR" );
country.setPopulation( 14805000 );
countries.add( country );

country = new Country();
country.setName( "コートジボワール" );
country.setCurrency( "XOF" );
country.setPopulation( 44904000 );
countries.add( country );

このマップのリストの内容は、以下のようなコードで表示できます。

//////////////////////////////////////////////////////////////////
// 各項目の最大長を求める。
//////////////////////////////////////////////////////////////////
int nameLen = length( "名前" );
int currencyLen = length( "通貨" );
int populationLen = length( "人口" );
for ( int i = 0; i < countries.size(); ++i ) {
	Country country = countries.get( i );
	String name =  country.getName();
	String currency =  country.getCurrency();
	String population =  country.getPopulation().toString();
	
	if ( length( name ) > nameLen ) {
		nameLen = length( name );
	}
	if ( length( currency ) > currencyLen ) {
		currencyLen = length( currency );
	}
	if ( length( population )  > populationLen ) {
		populationLen = length( population );
	}
}

//////////////////////////////////////////////////////////////////
// データをテーブルの形で出力する。
//////////////////////////////////////////////////////////////////

// 区切り文字列を作成する。
String separator = "+" + padding( "", nameLen, '-' )
	+ "+" + padding( "", currencyLen, '-' )
	+ "+" + padding( "", populationLen, '-' ) + "+";

// 区切り文字列を出力する。
System.out.println( separator );

// ヘッダ文字列を出力する。
System.out.println( "|" + padding( "名前", nameLen )
	+ "|" + padding( "通貨", currencyLen )
	+ "|" + padding( "人口", populationLen ) + "|" );

// 区切り文字列を出力する。
System.out.println( separator );

// データを出力する。
for ( int i = 0; i < countries.size(); ++i ) {
	Country country = countries.get( i );
	String name =  country.getName();
	String currency =  country.getCurrency();
	String population =  country.getPopulation().toString();
	
	System.out.println( "|" + padding( name, nameLen )
		+ "|" + padding( currency, currencyLen )
		+ "|" + padding( population, populationLen ) + "|" );
}

// 区切り文字列を出力する。
System.out.println( separator );

…

//////////////////////////////////////////////////////////////////
// 以下、ユーティリティメソッド
//////////////////////////////////////////////////////////////////

/* 文字列のバイト数を取得する。 */
private static int length( String str ) {
	return str.getBytes().length;
}

/* 文字列を空白でパディングする。 */
private static String padding( String str, int length ) {
	return padding( str, length, ' ' );
}

/* 文字列を指定した文字でパディングする。 */
private static String padding( String str, int length, char padChar ) {
	int spaceCount = length - str.getBytes().length;
	
	StringBuffer buf = new StringBuffer();
	for ( int i = 0; i < spaceCount; ++i ) {
		buf.append( padChar );
	}
	
	return str + buf.toString();
}

このコードの実行結果は以下の通りです。

+----------------+----+---------+
|名前            |通貨|人口     |
+----------------+----+---------+
|日本            |JPY |127156000|
|フランス        |EUR |65073482 |
|スペイン        |EUR |44904000 |
|ロシア          |RUB |141903979|
|ベトナム        |VND |84238000 |
|カンボジア      |KHR |14805000 |
|コートジボワール|XOF |44904000 |
+----------------+----+---------+

■抽出

複数のデータの中から、特定の条件を満たすデータを抽出するアルゴリズムです。
例として、商品データproductsから特定の条件を満たすデータを抽出します。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////
/**
 * 商品データ
 */
class Product {
	private String product_id;		// 商品ID
	private String product_name;	// 商品名
	private Integer price;			// 価格
	
	public void setProduct_id( String product_id ) {
		this.product_id = product_id;
	}
	
	public String getProduct_id() {
		return product_id;
	}
	
	public void setProduct_name( String product_name ) {
		this.product_name = product_name;
	}
	
	public String getProduct_name() {
		return product_name;
	}

	public void setPrice( Integer price ) {
		this.price = price;
	}
	
	public Integer getPrice() {
		return price;
	}
}

//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////
List> products = new ArrayList>();

Map product;

product = new HashMap();
product.put( "product_id", "1010" );
product.put( "product_name", "えんぴつ" );
product.put( "price", 80 );
products.add( product );

product = new HashMap();
product.put( "product_id", "1020" );
product.put( "product_name", "ボールペン" );
product.put( "price", 100 );
products.add( product );

product = new HashMap();
product.put( "product_id", "1030" );
product.put( "product_name", "消しゴム" );
product.put( "price", 100 );
products.add( product );

product = new HashMap();
product.put( "product_id", "2010" );
product.put( "product_name", "定規" );
product.put( "price", 140 );
products.add( product );

product = new HashMap();
product.put( "product_id", "2020" );
product.put( "product_name", "コンパス" );
product.put( "price", 300 );
products.add( product );

product = new HashMap();
product.put( "product_id", "3010" );
product.put( "product_name", "のり" );
product.put( "price", 200 );
products.add( product );

商品データproductsを表示すると、以下のようになります。

+------+----------+----+
|商品ID|商品名    |価格|
+------+----------+----+
|1010  |えんぴつ  |80  |
|1020  |ボールペン|100 |
|1030  |消しゴム  |100 |
|2010  |定規      |140 |
|2020  |コンパス  |300 |
|3010  |のり      |200 |
+------+----------+----+


以下のコードは、商品データproductsから「price > 100」を満たすデータを抽出します。

// 抽出結果を格納するリスト
List results = new ArrayList();

// すべての商品データについて繰り返す。
for ( int i = 0; i < products.size(); ++i ) {
	product = products.get( i );
	
	// 商品データのpriceが100より大きいことを確認する。
	Integer price = product.getPrice();
	if ( price > 100 ) {
		// 商品データを抽出結果に追加する。
		results.add( product );
	}
}

抽出結果は、変数resultsに格納されます。抽出結果resultを表示すると、以下のようになります。

+------+--------+----+
|商品ID|商品名  |価格|
+------+--------+----+
|2010  |定規    |140 |
|2020  |コンパス|300 |
|3010  |のり    |200 |
+------+--------+----+

■ソート

複数のデータを、特定の条件でソートするアルゴリズムです

Javaでのリストのソート

ソートの例の前に、Javaでのリストのソートについて説明します。
リストをソートするには、Collectionsクラスのsort()メソッドを使用します。

List list = new ArrayList();
list.add( 13 );
list.add( 43 );
list.add( 22 );
list.add( 234 );

Collections.sort( list, new Comparator() {
	public  int compare( Integer a, Integer b ) {
		// 引数1と引数2はそれぞれリスト中の値
		
		// compareTo()メソッドにより引数の大小比較を行う。
		// ・引数2の方が大きければ、戻り値は正の整数: 引数2→引数1の順に並ぶ。
		// ・引数同士が一致すれば、戻り値は0: 引数1と引数2は同列。
		// ・引数1の方が大きければ、戻り値は負の整数: 引数1→引数2の順に並ぶ。
		return  b.compareTo( a );
	}
} );

ソートの並び順は、sort()メソッドの引数に渡すComparatorの実装クラス中のcompare()メソッドで決めます。

compare()メソッドには引数としてリストの要素が2つずつ渡されます。引数2→引数1の順に並べたい場合は正の値を、引数1と引数2を同列にしたい場合は0を、引数1→引数2の順に並べたい場合は負の値を、compare()メソッドの戻り値として返します。

なお、上記のコードはリストの要素を「数値の降順」にソートします。

ソートの例(五十音順)

それでは、ソートの例を挙げます。
例として、売上データsalesを特定の項目の「五十音順」にソートします。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////
/**
 * 売上データ
 */
class Sale {
	private String sales_date;	// 売上日
	private String sales_no;	// 売上番号
	private String product_id;	// 商品ID
	private Integer amount;		// 数量

	public void setSales_date( String sales_date ) {
		this.sales_date = sales_date;
	}
	
	public String getSales_date() {
		return sales_date;
	}
	
	public void setSales_no( String sales_no ) {
		this.sales_no = sales_no;
	}
	
	public String getSales_no() {
		return sales_no;
	}
	
	public void setProduct_id( String product_id ) {
		this.product_id = product_id;
	}
	
	public String getProduct_id() {
		return product_id;
	}
	
	public void setAmount( Integer amount ) {
		this.amount = amount;
	}
	
	public Integer getAmount() {
		return amount;
	}
}

//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////
List sales = new ArrayList();
Sale sale;

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00001" );
sale.setProduct_id( "1020" );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00002" );
sale.setProduct_id( "1010" );
sale.setAmount( 5 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00003" );
sale.setProduct_id( "3010" );
sale.setAmount( 20 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00001" );
sale.setProduct_id( "1030" );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00002" );
sale.setProduct_id( "1020" );
sale.setAmount( 15 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00001" );
sale.setProduct_id( "2020" );
sale.setAmount( 30 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00002" );
sale.setProduct_id( "3010" );
sale.setAmount( 20 );
sales.add( sale );

売上データsalesを表示すると、以下のようになります。

+--------+--------+------+----+
|売上日  |売上番号|商品ID|数量|
+--------+--------+------+----+
|20090702|00001   |1020  |10  |
|20090702|00002   |1010  |5   |
|20090702|00003   |3010  |20  |
|20090703|00001   |1030  |10  |
|20090703|00002   |1020  |15  |
|20090704|00001   |2020  |30  |
|20090704|00002   |3010  |20  |
+--------+--------+------+----+


以下のコードは、売上データsalesを「五十音順でsales_noの昇順」にソートします。

Collections.sort( sales, new Comparator() {
	public int compare( Sale sale1, Sale sale2 ) {
		// 引数1と引数2はそれぞれ売上データ。
		
		// 売上データからsales_noを取得する。
		String sales_no1 = sale1.getSales_no();
		String sales_no2 = sale2.getSales_no();

		////////////////////////////////////////////
		// sales_noを比較する。
		////////////////////////////////////////////

		// compareToによりproduct_idの大小を比較する。
		// ・引数2のproduct_idの方が大きければ、戻り値は正の整数: 引数2→引数1の順に並ぶ。
		// ・product_idが一致すれば、戻り値は0: 引数1と引数2の同列。
		// ・引数1のproduct_idの方が大きければ、戻り値は負の整数: 引数1→引数2の順に並ぶ。
		return sales_no1.compareTo( sales_no2 );
	}
} );

ソート後の売上データsalesを表示すると、以下のようになります。

+--------+--------+------+----+
|売上日  |売上番号|商品ID|数量|
+--------+--------+------+----+
|20090702|00001   |1020  |10  |
|20090703|00001   |1030  |10  |
|20090704|00001   |2020  |30  |
|20090702|00002   |1010  |5   |
|20090703|00002   |1020  |15  |
|20090704|00002   |3010  |20  |
|20090702|00003   |3010  |20  |
+--------+--------+------+----+
ソートの例(数値順)

例をもう一つ挙げます。商品データproductsを特定の項目の「数値順」にソートします。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////
/**
 * 商品データ
 */
class Product {
	private String product_id;		// 商品ID
	private String product_name;	// 商品名
	private Integer price;			// 価格
	
	public void setProduct_id( String product_id ) {
		this.product_id = product_id;
	}
	
	public String getProduct_id() {
		return product_id;
	}
	
	public void setProduct_name( String product_name ) {
		this.product_name = product_name;
	}
	
	public String getProduct_name() {
		return product_name;
	}
	
	public void setPrice( Integer price ) {
		this.price = price;
	}
	
	public Integer getPrice() {
		return price;
	}
}

//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////
List products = new ArrayList();
Product product;

product = new Product();
product.setProduct_id( "2010" );
product.setProduct_name( "定規" );
product.setPrice( 140 );
products.add( product );

product = new Product();
product.setProduct_id( "2020" );
product.setProduct_name( "コンパス" );
product.setPrice( 300 );
products.add( product );

product = new Product();
product.setProduct_id( "3010" );
product.setProduct_name( "のり" );
product.setPrice( 200 );
products.add( product );

product = new Product();
product.setProduct_id( "1030" );
product.setProduct_name( "消しゴム" );
product.setPrice( 100 );
products.add( product );

product = new Product();
product.setProduct_id( "1020" );
product.setProduct_name( "ボールペン" );
product.setPrice( 100 );
products.add( product );

product = new Product();
product.setProduct_id( "1010" );
product.setProduct_name( "えんぴつ" );
product.setPrice( 80 );
products.add( product );

商品データproductsを表示すると、以下のようになります。

+------+----------+----+
|商品ID|商品名    |価格|
+------+----------+----+
|2010  |定規      |140 |
|2020  |コンパス  |300 |
|3010  |のり      |200 |
|1030  |消しゴム  |100 |
|1020  |ボールペン|100 |
|1010  |えんぴつ  |80  |
+------+----------+----+


以下のコードは、商品データproductsを「数値順でproduct_idの降順」にソートします。

Collections.sort( products, new Comparator() {
	public int compare( Product product1, Product product2 ) {
		// 引数1と引数2はそれぞれ商品データ。
		
		// 商品データのproduct_idを取得する。
		String product_id1 = product1.getProduct_id();
		String product_id2 = product2.getProduct_id();
	
		////////////////////////////////////////////
		// product_idを比較する。
		////////////////////////////////////////////

		// compareTo()メソッドによりproduct_idの大小を比較する。
		// ・引数2のproduct_idの方が大きければ、戻り値は正の整数: 引数2→引数1の順に並ぶ。
		// ・product_idが一致すれば、戻り値は0: 引数1と引数2の同列。
		// ・引数1のproduct_idの方が大きければ、戻り値は負の整数: 引数1→引数2の順に並ぶ。
		return product_id2.compareTo( product_id1 );
	}
 } );

ソート後の商品データproductsを表示すると、以下のようになります。

+------+----------+----+
|商品ID|商品名    |価格|
+------+----------+----+
|3010  |のり      |200 |
|2020  |コンパス  |300 |
|2010  |定規      |140 |
|1030  |消しゴム  |100 |
|1020  |ボールペン|100 |
|1010  |えんぴつ  |80  |
+------+----------+----+

■結合

2種類のデータを、特定の条件で結合するアルゴリズムです。
例として、商品データproductsと売上データsalesを結合します。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////
/**
 * 商品データ
 */
class Product {
	private String product_id;		// 商品ID
	private String product_name;	// 商品名
	private Integer price;			// 価格
	
	public void setProduct_id( String product_id ) {
		this.product_id = product_id;
	}
	
	public String getProduct_id() {
		return product_id;
	}
	
	public void setProduct_name( String product_name ) {
		this.product_name = product_name;
	}
	
	public String getProduct_name() {
		return product_name;
	}
	
	public void setPrice( Integer price ) {
		this.price = price;
	}
	
	public Integer getPrice() {
		return price;
	}
}

/**
 * 売上データ
 */
class Sale {
	private String sales_date;		// 売上日
	private String sales_no;		// 売上番号
	private String product_id;		// 商品ID
	private String product_name;	// 商品名
	private Integer amount;			// 数量
	private Integer price;			// 価格

	public void setSales_date( String sales_date ) {
		this.sales_date = sales_date;
	}
	
	public String getSales_date() {
		return sales_date;
	}
	
	public void setSales_no( String sales_no ) {
		this.sales_no = sales_no;
	}
	
	public String getSales_no() {
		return sales_no;
	}
	
	public void setProduct_id( String product_id ) {
		this.product_id = product_id;
	}
	
	public String getProduct_id() {
		return product_id;
	}
	
	public void setProduct_name( String product_name ) {
		this.product_name = product_name;
	}
	
	public String getProduct_name() {
		return product_name;
	}
	
	public void setAmount( Integer amount ) {
		this.amount = amount;
	}
	
	public Integer getAmount() {
		return amount;
	}
	
	public void setPrice( Integer price ) {
		this.price = price;
	}
	
	public Integer getPrice() {
		return price;
	}
}

//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////
List products = new ArrayList();

Product product;

product = new Product();
product.setProduct_id( "1010" );
product.setProduct_name( "えんぴつ" );
product.setPrice( 80 );
products.add( product );

product = new Product();
product.setProduct_id( "1020" );
product.setProduct_name( "ボールペン" );
product.setPrice( 100 );
products.add( product );

product = new Product();
product.setProduct_id( "1030" );
product.setProduct_name( "消しゴム" );
product.setPrice( 100 );
products.add( product );

product = new Product();
product.setProduct_id( "2010" );
product.setProduct_name( "定規" );
product.setPrice( 140 );
products.add( product );

product = new Product();
product.setProduct_id( "2020" );
product.setProduct_name( "コンパス" );
product.setPrice( 300 );
products.add( product );

product = new Product();
product.setProduct_id( "3010" );
product.setProduct_name( "のり" );
product.setPrice( 200 );
products.add( product );


List sales = new ArrayList();

Sale sale;

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00001" );
sale.setProduct_id( "1020" );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00002" );
sale.setProduct_id( "1010" );
sale.setAmount( 5 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00003" );
sale.setProduct_id( "3010" );
sale.setAmount( 20 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00001" );
sale.setProduct_id( "1030" );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00002" );
sale.setProduct_id( "1020" );
sale.setAmount( 15 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00001" );
sale.setProduct_id( "2020" );
sale.setAmount( 30 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00002" );
sale.setProduct_id( "3010" );
sale.setAmount( 20 );
sales.add( sale );

商品データproductsを表示すると以下のようになります。

+------+----------+----+
|商品ID|商品名    |価格|
+------+----------+----+
|1010  |えんぴつ  |80  |
|1020  |ボールペン|100 |
|1030  |消しゴム  |100 |
|2010  |定規      |140 |
|2020  |コンパス  |300 |
|3010  |のり      |200 |
+------+----------+----+

また、売上データsalesを表示すると以下のようになります。

+--------+--------+------+----+
|売上日  |売上番号|商品ID|数量|
+--------+--------+------+----+
|20090702|00001   |1020  |10  |
|20090702|00002   |1010  |5   |
|20090702|00003   |3010  |20  |
|20090703|00001   |1030  |10  |
|20090703|00002   |1020  |15  |
|20090704|00001   |2020  |30  |
|20090704|00002   |3010  |20  |
+--------+--------+------+----+


以下のコードは、商品データと売上データをproduct_idをキーとして結合します。

/////////////////////////////////////////////////////////////////////////////////
// ハッシュテーブルを作成し、 product_idをキーとして商品データを取得できるようにする。
/////////////////////////////////////////////////////////////////////////////////

// ハッシュテーブル
Map hashTable = new HashMap();

// すべての商品データについて繰り返す。
for ( int i = 0; i < products.size(); ++i ) {
	product = products.get( i );
	
	// 商品データのproduct_idを取得する。
	String key = product.getProduct_id();
	
	// product_idをキーとして、商品データをハッシュテーブルに格納する。
	hashTable.put( key, product );
}

/////////////////////////////////////////////////////////////////////////////////
// 売上データと商品データを結合する。
/////////////////////////////////////////////////////////////////////////////////

// すべての売上データについて繰り返す。
for ( int i = 0; i < sales.size(); ++i ) {
	sale = sales.get( i );
	
	// 売上データのproduct_idを取得する。
	String product_id = sale.getProduct_id();
	
	// product_idをキーとして、商品データをハッシュテーブルから取得する。
	product = hashTable.get( product_id );
	if ( product != null ) {
		// 商品データを取得できた場合:
		
		// 商品データの値を売上データに格納する。
		sale.setProduct_name( product.getProduct_name() );
		sale.setPrice( product.getPrice() );
	}
}

結合後の売上データsalsesを表示すると、以下のようになります。

+--------+--------+------+----------+----+----+
|売上日  |売上番号|商品ID|商品名    |数量|価格|
+--------+--------+------+----------+----+----+
|20090702|00001   |1020  |ボールペン|10  |100 |
|20090702|00002   |1010  |えんぴつ  |5   |80  |
|20090702|00003   |3010  |のり      |20  |200 |
|20090703|00001   |1030  |消しゴム  |10  |100 |
|20090703|00002   |1020  |ボールペン|15  |100 |
|20090704|00001   |2020  |コンパス  |30  |300 |
|20090704|00002   |3010  |のり      |20  |200 |
+--------+--------+------+----------+----+----+

■集計

複数のデータを特定の条件で集計するアルゴリズムです。
例として、売上データsalesを集計します。

//////////////////////////////////////////////////////////////////
// ビーン
//////////////////////////////////////////////////////////////////
/**
 * 売上データ
 */
class Sale {
	private String sales_date;		// 売上日
	private String sales_no;		// 売上番号
	private String product_name;	// 商品名
	private Integer price;			// 価格
	private Integer amount;			// 数量

	public void setSales_date( String sales_date ) {
		this.sales_date = sales_date;
	}
	
	public String getSales_date() {
		return sales_date;
	}
	
	public void setSales_no( String sales_no ) {
		this.sales_no = sales_no;
	}
	
	public String getSales_no() {
		return sales_no;
	}
	
	public void setProduct_name( String product_name ) {
		this.product_name = product_name;
	}
	
	public String getProduct_name() {
		return product_name;
	}
	
	public void setPrice( Integer price ) {
		this.price = price;
	}
	
	public Integer getPrice() {
		return price;
	}
	
	public void setAmount( Integer amount ) {
		this.amount = amount;
	}
	
	public Integer getAmount() {
		return amount;
	}
}

/**
 * 集計結果
 */
class Result {
	private String sales_date;	// 売上日
	private Integer amount;		// 合計数量
	private Integer total;		// 合計売上高
	
	public void setSales_date( String sales_date ) {
		this.sales_date = sales_date;
	}
	
	public String getSales_date() {
		return sales_date;
	}
	
	public void setAmount( Integer amount ) {
		this.amount = amount;
	}
	
	public Integer getAmount() {
		return amount;
	}
	
	public void setTotal( Integer total ) {
		this.total = total;
	}
	
	public Integer getTotal() {
		return total;
	}
}


//////////////////////////////////////////////////////////////////
// ビーンのリストの作成
//////////////////////////////////////////////////////////////////
List sales = new ArrayList();

Sale sale;

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00001" );
sale.setProduct_name( "ボールペン" );
sale.setPrice( 100 );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00002" );
sale.setProduct_name( "えんぴつ" );
sale.setPrice( 80 );
sale.setAmount( 5 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090702" );
sale.setSales_no( "00003" );
sale.setProduct_name( "のり" );
sale.setPrice( 200 );
sale.setAmount( 20 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00001" );
sale.setProduct_name( "消しゴム" );
sale.setPrice( 100 );
sale.setAmount( 10 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090703" );
sale.setSales_no( "00002" );
sale.setProduct_name( "ボールペン" );
sale.setPrice( 100 );
sale.setAmount( 15 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00001" );
sale.setProduct_name( "コンパス" );
sale.setPrice( 300 );
sale.setAmount( 30 );
sales.add( sale );

sale = new Sale();
sale.setSales_date( "20090704" );
sale.setSales_no( "00002" );
sale.setProduct_name( "のり" );
sale.setPrice( 200 );
sale.setAmount( 20 );
sales.add( sale );

売上データsalesを表示すると以下のようになります。

+--------+--------+----------+----+----+
|売上日  |売上番号|商品名    |価格|数量|
+--------+--------+----------+----+----+
|20090702|00001   |ボールペン|100 |10  |
|20090702|00002   |えんぴつ  |80  |5   |
|20090702|00003   |のり      |200 |20  |
|20090703|00001   |消しゴム  |100 |10  |
|20090703|00002   |ボールペン|100 |15  |
|20090704|00001   |コンパス  |300 |30  |
|20090704|00002   |のり      |200 |20  |
+--------+--------+----------+----+----+


以下のコードは、salesを集計してsales_date毎の合計数量と合計売上高を求めます。

///////////////////////////////////////////////////////
// 集計結果の初期化
///////////////////////////////////////////////////////

// 集計結果を一時的に格納するマップ
Map resultsMap = new HashMap();

// すべての売上データについて繰り返す。
for ( int i = 0; i < sales.size(); ++i ) {
	sale = sales.get( i );

	// 売上データのsales_dateを取得する。
	String sales_date = sale.getSales_date();
	
	if ( ! resultsMap.containsKey( sales_date ) ) {
		// マップにキーsales_dateが含まれていない:
		
		// 集計結果の初期値を生成する。
		Result result = new Result();
		result.setSales_date( sales_date );
		result.setAmount( 0 );
		result.setTotal( 0 );

		// 生成した初期値をキーsales_dateに関連付けてマップに格納する。
		resultsMap.put( sales_date, result );
	}
}	

///////////////////////////////////////////////////////
// salesを集計
///////////////////////////////////////////////////////

// すべての売上データについて繰り返す。
for ( int i = 0; i < sales.size(); ++i ) {
	sale = sales.get( i );
	
	// 売上データのsales_dateを取得する。
	String sales_date = sale.getSales_date();
	
	// キーsales_dateに関連付く集計結果をオブジェクトから取得する。
	Result result = resultsMap.get( sales_date );

	// 売上データのamountを集計結果に足し合わせる。
	Integer s_amount = sale.getAmount();
	Integer r_amount = result.getAmount();
	result.setAmount( r_amount + s_amount );
	// 売上データのpriceとamountとを掛けた値を集計結果に足し合わせる。
	Integer s_price = sale.getPrice();
	Integer r_total = result.getTotal();
	result.setTotal( r_total + s_price * s_amount );
}

///////////////////////////////////////////////////////
// 集計結果をリストに移し替え
///////////////////////////////////////////////////////

List results = new ArrayList();

// 一時マップの全てのキーとデータについて繰り返す。
for ( String sales_date : resultsMap.keySet() ) {
	Result result = resultsMap.get( sales_date );
	
	// データをリストに追加する
	results.add( result );
}

///////////////////////////////////////////////////////
// 集計結果をsales_dateの昇順にソート
///////////////////////////////////////////////////////

Collections.sort( results, new Comparator() {
	public int compare( Result result1, Result result2 ) {
		String sales_date1 = result1.getSales_date();
		String sales_date2 = result2.getSales_date();

		return sales_date1.compareTo( sales_date2 );
	}
} );

集計結果は変数resultsに格納されます。集計結果resultsを表示すると以下のようになります。

+--------+--------+----------+
|売上日  |合計数量|合計売上高|
+--------+--------+----------+
|20090702|35      |5400      |
|20090703|25      |2500      |
|20090704|50      |13000     |
+--------+--------+----------+