質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

Q&A

解決済

3回答

8832閲覧

LINQで空要素を後ろに配置して昇順で並び替えるには

Zaki1192

総合スコア4

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

LINQ

LINQとはLanguage INtegrated Queryの略で、「統合言語クエリ」という意味です。C#やVisual Basicといった言語のコード内に記述することができるクエリです。

0グッド

0クリップ

投稿2021/12/01 05:40

前提・実現したいこと

LINQのorderbyメソッドを用いてデータを昇順で並び替えをすると空要素(Null/empty)が先頭にきます。
空要素を後ろに配置するように昇順で並び替えたいです。
List型ではうまくいきましたが、datarow型でのラムダ式の記述でつまづいてしまったため質問させていただきました。

発生している問題・エラーメッセージ

'Datarow'から'string'へ変換することはできません

該当のソースコード

C#

1 DataTable dt = new DataTable(); 2 dt.Columns.Add("No", typeof(int)); 3 dt.Columns.Add("Name", typeof(string)); 4 5 dt.Rows.Add(1,"B"); 6 dt.Rows.Add(2,""); 7 dt.Rows.Add(3,"C"); 8 dt.Rows.Add(4,"A"); 9 10 DataRow[] rows = dt.AsEnumerable() 11 .OrderByDescending(x => !string.IsNullOrEmpty(x)["Name"])//構文エラー 12 .ThenBy(x => x) 13 .ToArray(); 14 DataTable dt2 = rows.CopyToDataTable();

試したこと

Listでの並び替え

C#

1 var lst = new List<string>() { "B", null, "C","A" }; 2 3 var orderbylst = lst.OrderBy(x => x); //null,"A","B","C" 4 var orderbylst2 = lst.OrderByDescending(x => (!string.IsNullOrEmpty(x));//"B","C","A",null 5 var orderbylst3 = lst.OrderByDescending(x => !string.IsNullOrEmpty(x)) 6 .ThenBy(x => x);//"A","B","C",null

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/12/01 06:33

DataRowは"No"と"Name"のカラムが2つありますが、ソートの際は"No"は問わないのでしょうか。 例えば{{No=1, Name=""}, {No=2, Name=""}}のような場合、どうなることを想定していますか。
Zaki1192

2021/12/01 06:54

質問ありがとうございます。 カラム"No"に対する記述がなくて申し訳ありません。 "Name"で空要素が複数ある場合は、その中で"No"での昇順になることを想定しています。 {No=1, Name=""}、{No=2, Name=""}、{No=3, Name="C"}、{No=4, Name="A"} ⇓    {No=4, Name="A"}、{No=3, Name="C"}、{No=1, Name=""}、{No=2, Name=""}
退会済みユーザー

退会済みユーザー

2021/12/01 07:19 編集

> .OrderByDescending(x => !string.IsNullOrEmpty(x)["Name"])//構文エラー エラーメッセージは string.IsNullOrEmpty(x) の引数 x の型が DataRow だからダメだと言っているのですよね? であれば、 !string.IsNullOrEmpty(x)["Name"] に代えて !string.IsNullOrEmpty(x.Field<string>("Name")) としてみたらどうなりますか?
BluOxy

2021/12/01 07:15

{No=4, Name="A"}, {No=5, Name="A"} のときも昇順でしょうか
退会済みユーザー

退会済みユーザー

2021/12/01 07:31

.ThenBy(x => x) ←やってみましたが、これもダメでした。回答欄に書いておきます。
Zuishin

2021/12/01 07:35

まず OrderBy で空白を後にし、ThenBy で昇順に並べ替えると良いと思います。
Zaki1192

2021/12/01 07:43 編集

SurferOnWwwさん 質問ありがとうございます。 DataRow[] rows = dt.AsEnumerable()            .OrderByDescending(x => !string.IsNullOrEmpty(x.Field<string>("Name"))) .ThenBy(x => x)            .ToArray(); 上記で実装してみたところ System.ArgumentException: '少なくとも 1 つのオブジェクトで IComparable を実装しなければなりません。' となりました。 <参考> https://www.webdevqa.jp.net/ja/c%23/%E5%B0%91%E3%81%AA%E3%81%8F%E3%81%A8%E3%82%821%E3%81%A4%E3%81%AE%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%8Cicomparable%E3%82%92%E5%AE%9F%E8%A3%85%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99/972695140/ 私自身仕組みの理解が追い付いていませんが、 キャストの方法が理解できていなかったため、非常に助かりました。 ありがとうございます。 追記 .ThenBy(x => x.Field<string>("Name"))の修正で対応できました。 ありがとうございます。
退会済みユーザー

退会済みユーザー

2021/12/01 07:41

回答欄を見てください。そこのところも解決しました。
guest

回答3

0

独自のIComparerを実装したクラスを作ってください。
Compareの中身を弄れば、好きなようにソートできます。
IComparer.Compare(Object, Object) メソッド

cs

1using System; 2using System.Collections.Generic; 3using System.Data; 4using System.Linq; 5 6class Program 7{ 8 class CustomComparer : IComparer<DataRow> 9 { 10 public int Compare(DataRow x, DataRow y) 11 { 12 var name_x = Convert.ToString(x["Name"]); 13 var name_y = Convert.ToString(y["Name"]); 14 if ( name_x==name_y ) 15 { 16 return 0; 17 } 18 if( String.IsNullOrEmpty(name_x) ) 19 { 20 return 1; 21 } 22 if (String.IsNullOrEmpty(name_y)) 23 { 24 return -1; 25 } 26 return string.Compare(name_x, name_y); 27 } 28 } 29 30 static void Main() 31 { 32 DataTable dt = new DataTable(); 33 dt.Columns.Add("No", typeof(int)); 34 dt.Columns.Add("Name", typeof(string)); 35 36 dt.Rows.Add(1, "B"); 37 dt.Rows.Add(2, ""); 38 dt.Rows.Add(3, "C"); 39 dt.Rows.Add(4, "A"); 40 41 DataTable dt2 = dt.AsEnumerable() 42 .OrderBy(x => x, new CustomComparer()) 43 .CopyToDataTable(); 44 } 45}

(実行結果)
実行結果

手抜きするなら、空白を絶対最後尾に来る文字列に置換するとか…

cs

1DataTable dt2 = dt.AsEnumerable() 2 .OrderBy(x => String.IsNullOrEmpty(x["Name"].ToString()) ? "ZZZ" : x["Name"]) 3 .CopyToDataTable();

投稿2021/12/01 07:13

編集2021/12/01 07:35
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zaki1192

2021/12/01 08:45

条件が複雑になる場合は独自のIComparerクラスを使ってみます! "ZZZ"で置換するアイディアも参考になりました。 実際に検証までしていただいてベストアンサーではなくて申し訳ありません。 回答ありがとうございました。
guest

0

OrderBy で null もしくは空文字か否かで並び替えてください。
boolean は数値表現において false は 0, true は 1 となりますのでその順番に並び替えられます。

C#

1var rows = dt.AsEnumerable() 2 .OrderBy(x => string.IsNullOrEmpty(x["Name"] as string)) 3 .ThenBy(x => x["Name"]) 4 .ThenBy(x => x["No"]) 5 .ToArray();

投稿2021/12/01 07:47

BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zaki1192

2021/12/01 09:00

最初にOrderByDescendingの降順で空要素を下げることが絶対だと思っていましたが、 orderbyでの記述からはじめることもできるんですね。 他の回答とも併せてロジックを理解していきたいと思います。 ありがとうございました。
BluOxy

2021/12/01 09:20

今回の OrderBy は昇順で空でない要素を先頭にしているだけで、していることは降順で空要素を末尾にすることと同じです。
guest

0

ベストアンサー

質問のコメント欄で、

.OrderByDescending(x => !string.IsNullOrEmpty(x)["Name"])//構文エラー

エラーメッセージは string.IsNullOrEmpty(x) の引数 x の型が DataRow だからダメだと言っているのですよね? であれば、 !string.IsNullOrEmpty(x)["Name"] に代えて !string.IsNullOrEmpty(x.Field<string>("Name")) としてみたらどうなりますか?

と書きましたが、それだけではダメで、.ThenBy(x => x) ←これもダメでした。以下のようにしたらどうでしょう? お試しください。

DataTable dt = new DataTable(); dt.Columns.Add("No", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Rows.Add(1, "B"); dt.Rows.Add(2, ""); dt.Rows.Add(3, "C"); dt.Rows.Add(4, "A"); DataRow[] rows = dt.AsEnumerable() .OrderByDescending(x => !string.IsNullOrEmpty(x.Field<string>("Name"))) .ThenBy(x => x.Field<string>("Name")) .ToArray(); DataTable dt2 = rows.CopyToDataTable();

イメージ説明

投稿2021/12/01 07:36

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zaki1192

2021/12/01 08:56

早々の回答ありがとうございました。 はじめての質問利用でしたが、非常に勉強になりました。 string str = (string)obj; string str = obj as string; コードの書き方の質問でしたが、 今まで気になっていなかった、キャスト演算子とas演算子など型変換の違いに注目することができました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問