6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

C#ソートメソッドまとめ

Posted at

はじめに

C#で使用するソート系メソッドをまとめました。
個人的な備忘録です。間違いなどあれば教えていただけると嬉しいです。

必要なusing文

using System;                    // Array.Sort用
using System.Collections.Generic; // List<T>用
using System.Linq;               // OrderBy, Where, Select用

配列のソート

Array.Sort() - 破壊的

int[] array = { 5, 2, 8, 1, 9 };
Array.Sort(array);               // 元の配列が変更される
// 結果: { 1, 2, 5, 8, 9 }

OrderBy() - 非破壊的

int[] array = { 5, 2, 8, 1, 9 };
var sorted = array.OrderBy(x => x).ToArray();
// 元の配列: { 5, 2, 8, 1, 9 } (変更されない)
// sorted: { 1, 2, 5, 8, 9 }

元データを保持したい場合

int[] original = { 5, 2, 8, 1, 9 };

// 方法1: Clone()を使用
int[] copy = (int[])original.Clone();
Array.Sort(copy);

// 方法2: OrderBy()を使用
var sorted = original.OrderBy(x => x).ToArray();

Listのソート

List.Sort() - 破壊的

var list = new List<int> { 5, 2, 8, 1, 9 };
list.Sort();                     // 元のリストが変更される
// 結果: { 1, 2, 5, 8, 9 }

OrderBy() - 非破壊的

var list = new List<int> { 5, 2, 8, 1, 9 };
var sorted = list.OrderBy(x => x).ToList();
// 元のリスト: { 5, 2, 8, 1, 9 } (変更されない)
// sorted: { 1, 2, 5, 8, 9 }

カスタムソート

var list = new List<int> { 5, 2, 8, 1, 9 };

// 降順
list.Sort((x, y) => y.CompareTo(x));

// 絶対値でソート
list.Sort((x, y) => Math.Abs(x).CompareTo(Math.Abs(y)));

LINQ基本メソッド

OrderBy() / OrderByDescending()

var numbers = new List<int> { 5, 2, 8, 1, 9 };

var asc = numbers.OrderBy(x => x);           // 昇順
var desc = numbers.OrderByDescending(x => x); // 降順

ThenBy() / ThenByDescending()

var people = new List<(string Name, int Age)>
{
    ("田中", 25), ("佐藤", 25), ("鈴木", 30)
};

var sorted = people
    .OrderBy(x => x.Age)      // まず年齢でソート
    .ThenBy(x => x.Name)      // 同じ年齢なら名前でソート
    .ToList();

Where() - フィルタリング

var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var evenNumbers = numbers.Where(x => x % 2 == 0);     // 偶数のみ
var greaterThan5 = numbers.Where(x => x > 5);         // 5より大きい
var range = numbers.Where(x => x >= 3 && x <= 7);     // 3以上7以下

Select() - 変換

var numbers = new List<int> { 1, 2, 3, 4, 5 };

var doubled = numbers.Select(x => x * 2);              // 2倍
var strings = numbers.Select(x => $"数字{x}");         // 文字列変換
var squared = numbers.Select(x => x * x);              // 平方

Reverse() - 順序逆転

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var reversed = numbers.Reverse();                      // 逆順

タプルのソート

基本的なタプルソート

var dates = new List<(int Month, int Day)>
{
    (3, 29), (1, 1), (1, 4), (12, 28), (4, 1)
};

// 月→日の順でソート
var sorted = dates.OrderBy(x => x.Month).ThenBy(x => x.Day).ToList();
// 結果: (1,1), (1,4), (3,29), (4,1), (12,28)

複雑なタプルソート

var people = new List<(string Name, int Age, string City)>
{
    ("田中", 25, "東京"), ("佐藤", 30, "大阪"), ("鈴木", 25, "東京")
};

// 年齢→名前の順でソート
var sorted = people.OrderBy(x => x.Age).ThenBy(x => x.Name).ToList();

// 都市→年齢→名前の順でソート
var multiSort = people
    .OrderBy(x => x.City)
    .ThenBy(x => x.Age)
    .ThenBy(x => x.Name)
    .ToList();

4月2日から始まる年間カレンダーソート

var dates = new List<(int Month, int Day)>
{
    (3, 29), (1, 1), (1, 4), (12, 28), (4, 1), (4, 2)
};

// 4月2日を基準とした並び順
var yearFromApril = dates.OrderBy(x => 
{
    if (x.Month > 4 || (x.Month == 4 && x.Day >= 2))
        return x.Month * 100 + x.Day;      // 今年(ソート用キー値)
    else
        return (x.Month + 12) * 100 + x.Day; // 翌年扱い(ソート用キー値)
    // ※この計算はソート順を決めるためだけで、元のタプルは変更されない
}).ToList();
// 結果: (4,2), (12,28), (1,1), (1,4), (3,29), (4,1)

メソッドチェーン

var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

var result = numbers
    .Where(x => x % 2 == 0)        // 偶数のみ
    .Select(x => x * 3)            // 3倍
    .OrderByDescending(x => x)     // 降順
    .Take(3)                       // 上位3つ
    .ToList();
// 結果: { 30, 24, 18 }

ソート後の比較

var list1 = new List<int> { 5, 2, 8, 1, 9 };
var list2 = new List<int> { 1, 2, 5, 8, 9 };

// == では比較できない(参照比較のため)
Console.WriteLine(list1 == list2); // False(中身が同じでも異なるインスタンス)

// SequenceEqual で順序も含めて比較
Console.WriteLine(list1.SequenceEqual(list2)); // False(順序が違う)

// 先にソートしてから比較(順序無視で要素を比較)
var sortedList1 = list1.OrderBy(x => x).ToList();
var sortedList2 = list2.OrderBy(x => x).ToList();
var areEqualWhenSorted = sortedList1.SequenceEqual(sortedList2);
Console.WriteLine(areEqualWhenSorted); // True

使い分けガイド

元データを変更してもよい場合

  • 配列: Array.Sort()
  • List: list.Sort()

元データを保持したい場合

  • 配列: array.OrderBy(x => x).ToArray()
  • List: list.OrderBy(x => x).ToList()

複雑な条件でソート

  • 共通: OrderBy() + ThenBy()

Dictionaryのソート

var dict = new Dictionary<string, int> { {"a", 3}, {"b", 1}, {"c", 2} };

var sortedByKey = dict.OrderBy(x => x.Key);      // キーでソート
var sortedByValue = dict.OrderBy(x => x.Value);  // 値でソート

注意点

破壊的メソッド(元データ変更)

  • Array.Sort()
  • List.Sort()
  • List.Reverse()
  • Array.Reverse()

非破壊的メソッド(元データ保持)

  • OrderBy()
  • Where()
  • Select()
  • Reverse()(LINQ版)

OrderbyやWhereなどは遅延実行される

var query = numbers.Where(x => x > 5);  // まだ実行されない
var result = query.ToList();            // ここで実行される

よく使うパターン

年齢でソート、同じ年齢なら名前順

people.OrderBy(p => p.Age).ThenBy(p => p.Name)

偶数のみ取得して降順ソート

numbers.Where(x => x % 2 == 0).OrderByDescending(x => x)

名前を取得してアルファベット順

people.Select(p => p.Name).OrderBy(name => name)

上位3件を取得

numbers.OrderByDescending(x => x).Take(3)

対応表

コレクション Sort() OrderBy() 専用メソッド
int[] Array.Sort()
List -
Dictionary -
配列・リスト以外※ -

※IEnumerableを実装する型(HashSet、Queue、Stack等)

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?