CSVをソート (複数列指定)

ComparatorChain便利だった。

適当なライブラリを使ってCSVを読み込んでフィールドを文字列のリストにして、
それをさらに行数分リストにしたのを用意してソートする。

package demo;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.collections.comparators.ComparatorChain;

/** CSVデータソート用クラス */
public final class CSVSort {
	/**
	 * CSVをソートします
	 * @param csv csvデータ
	 * @param metaDatas ソート情報
	 */
	@SuppressWarnings("unchecked")
	public static void sort(List<List<String>> csv, List<SortMetaData> metaDatas) {
		if (metaDatas.isEmpty()) {
			return;
		}
		// ソート情報をキー順に並べ替え
		Collections.sort(metaDatas, new Comparator<SortMetaData>() {
			@Override
			public int compare(SortMetaData o1, SortMetaData o2) {
				return (o1.order < o2.order ? -1 : (o1.order == o2.order ? 0
						: 1));
			}
		});
		ComparatorChain cc = new ComparatorChain();
		for (final SortMetaData meta : metaDatas) {
			cc.addComparator(new Comparator<List<String>>() {
				@Override
				public int compare(List<String> o1, List<String> o2) {
					return o1.get(meta.colNo).compareTo(o2.get(meta.colNo));
				}
			}, !meta.isAscending);
		}
		// ソート
		Collections.sort(csv, cc);
	}

	/** ソート情報 */
	public static class SortMetaData {
		/** 列番号 */
		public final int colNo;
		/** キー順(何番目に有効にするか) */
		public final long order;
		/** 昇順の場合{@code true} */
		public final boolean isAscending;

		/**
		 * コンストラクタ
		 * @param colNos 列番号
		 * @param order キー順
		 * @param isAccending 昇順の場合{@code true}
		 */
		public SortMetaData(int colNos, long order, boolean isAccending) {
			this.colNo = colNos;
			this.order = order;
			this.isAscending = isAccending;
		}
	}
}

testコード

package demo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;
import demo.CSVSort.SortMetaData;

public class CSVSortTest extends TestCase {
	private static List<String> r(String... strings) {
		return Arrays.asList(strings);
	}

	private static String d(List<List<String>> csv) {
		StringBuilder sb = new StringBuilder();
		for (List<String> line : csv) {
			for (String field : line) {
				sb.append(field);
				sb.append(',');
			}
			sb.deleteCharAt(sb.length() - 1);
			sb.append('\n');
		}
		return sb.toString();
	}

	/** sort test */
	public void testSort() {
		List<List<String>> act = new ArrayList<List<String>>();
		// r()は文字列配列をリストにするメソッド
		act.add(r("100", "120", "110"));
		act.add(r("100", "110", "120"));
		act.add(r("200", "100", "200"));
		List<SortMetaData> metaList = new ArrayList<SortMetaData>();
		metaList.add(new SortMetaData(0, 1, false));
		metaList.add(new SortMetaData(1, 1, true));
		CSVSort.sort(act, metaList);
		List<List<String>> exp = new ArrayList<List<String>>();
		exp.add(r("200", "100", "200"));
		exp.add(r("100", "110", "120"));
		exp.add(r("100", "120", "110"));
		// d()はオブジェクトをダンプするメソッド
		assertEquals(d(exp), d(act));
		System.out.println(d(exp));
	}
}