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

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

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

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

Q&A

2回答

1037閲覧

Listの指定範囲の削除の方法

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

0グッド

1クリップ

投稿2021/06/05 03:40

下記の「ソートするため更新しなかった残り50個を削除したい」の部分のやり方ってもっとスマートな方法があるのでしょうか。

List.clearして再度追加するなどはここではしたくなく、
あくまですでにあるものに対しては更新、なければ追加

更新した範囲以外はリストから削除(次の処理であるソートに影響があるため)

リストをソート
ということをしたいです。

cs

1 public class TestClass 2 { 3 public int value; 4 public string name; 5 } 6 7 List<TestClass> list = new List<TestClass>(); 8 9 void InitList() 10 { 11 for (int i = 0; i < 100; i++) 12 { 13 TestClass t = new TestClass { value = i, name = i.ToString() }; 14 list.Add(t); 15 } 16 17 // リストの最初の50個を更新 18 int index; 19 for (index = 0; index < 50; index++) 20 { 21 UpdateList(index); 22 } 23 24 // ソートするため更新しなかった残り50個を削除したい ココ!!!!!! 25 if(index < (this.list.Count - 1)) 26 { 27 int next = index + 1; 28 this.list.RemoveRange(next, list.Count - next); 29 } 30 31 // ソート 32 } 33 34 void UpdateList(int index) 35 { 36 int val = index + 99999; 37 if (index < list.Count) // 範囲内の場合は「更新」 38 { 39 var t = this.list[index]; 40 t.value = val; 41 t.name = val.ToString(); 42 } 43 else// 範囲外の場合は「追加」 44 { 45 TestClass t = new TestClass { value = val, name = val.ToString() }; 46 list.Add(t); 47 } 48 }

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

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

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

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

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

YAmaGNZ

2021/06/05 03:52

示されたサンプルであればUpdateしたものだけ別のListにAddすればいいのではないかと思いますがそういうことではないんですよね?
退会済みユーザー

退会済みユーザー

2021/06/05 04:11

情報が不足していて申し訳ございません。 Listは記載されているList1つだけという前提での話となります。 質問とそれてしまい記載しませんでしたが、気にしていることはゴミができるだけ発生しないこと、コピーが発生しないことも意識しています。 ですので最初は全追加ですが以降は範囲内は更新などをしています。 C#の知識はそこまでないのでいろいろなサイトで参考にしたことを個人的にやっているだけですが・・・。
YAmaGNZ

2021/06/05 05:13 編集

例のソースを見たのですがよく分かりません。 UpdateListメソッドにてListにAddされたものも消すのですか? Listを得た時点で削除するものが分かる(例で言えばインデックス50~)のであれば、最初に消せばUpdateListメソッドにてListにAddされたものは除外できるかと思います。 ただ質問する為に端折ったであろう仕様も実際には関係しそうに感じます。
退会済みユーザー

退会済みユーザー

2021/06/05 05:22 編集

例えばですが、現在アクティブ状態のオブジェクトが100こあったとします。 TestClassのインスタンスを生成し情報を設定し、リスト作成します。 Value順(例)にソートし表示するようにします。 次任意のタイミングでサンプルした際、アクティブなオブジェクトは50個でした。 その50個の情報を設定しリストを作成します。(事前に100要素あるのでリスト内0~49までの情報を更新) value順のソートをしたいのですが残り50個は前の情報が入っており不要なので残りの50個をリストから削除したい。(ここの処理がもっとスマートに書けないものかと・・・) ID順にソートして表示。 ListをClearして再度1つずつ情報クラスを生成して入れるのもいいのですが、ごみが発生したり更新する方が使いまわしで良いのかなと思っている次第です。 よろしくお願いします。
YAmaGNZ

2021/06/05 07:28

1.アクティブなオブジェクト100個のList作成 2.アクティブなオブジェクトが50個になった 3.1で作成したListから2の段階でアクティブではないオブジェクトを削除する ということですか? 2でアクティブなオブジェクトというのは必ずListの先頭からX個という状態になるのですか? そうなのであればRemoveRangeにてそれ以降を消すというのでいいかと思います。 100個のListから何かしらの条件で消すオブジェクトが連続しないのであればループ(使用できるならLinqもあり)しRemoveAtなりで消すしかないかと思います。 具体的な処理が分からないので「次任意のタイミングでサンプルした際、アクティブなオブジェクトは50個でした。」という時点でアクティブなオブジェクトのリストが出来ているのではないかとも思ってしまいます。
gentaro

2021/06/05 07:38 編集

> ListをClearして再度1つずつ情報クラスを生成して入れるのもいいのですが、ごみが発生したり更新する方が使いまわしで良いのかなと思っている次第です。 その判断に至った理由は? 速度的にメチャクチャシビアで計測した結果それが最も現実的、とかいうのでなければ、わかりやすさ最優先で作ったほうがよっぽど良いと思うけども。 どうしてもその「オブジェクトを使い回す」という要件が必須というわけではない(実際にやってみて不都合がない)のであれば、より単純な方法で実装するべきでしょう。 別の手段で簡単に実現可能な事を、ロクな根拠もなく難しくするのは、バグを生むキッカケにしかならないので愚の骨頂。
退会済みユーザー

退会済みユーザー

2021/06/05 08:50

>gentaroさん >速度的にメチャクチャシビアで計測した結果それが最も現実的、とかいうのでなければ、わかりやすさ最優先で作ったほうがよっぽど良いと思うけども。 ごもっともだと思います。 >その判断に至った理由は? こちらがデバッグ機能として使う場合を想定して書いているからとなります。 スマートフォン端末などのデバッグ機能として使用したい場合デバッグ機能の処理が激重でもっさりして見えるとかなると困るためできるだけゴミなどが出ない方法はないかなと思い試している最中となります。
BeatStar

2021/06/05 08:54

他の方々も仰っているように、『仕様による』のではないかと思いますが。
退会済みユーザー

退会済みユーザー

2021/06/05 09:24

>YAmaGNZさん アクティブなオブジェクトが「A,B,C,D,E」とありオブジェクトを取得します 取得したオブジェクトの配列をループで回しそれぞれ「詳細クラス」を作成し詳細リストに追加します。 ※「詳細クラス」は質問で言う「TestClass」、「詳細リスト」は質問で言う「list」を指します。 2回目のサンプルでは「C,D,G,H」がアクティブだったとします。 また同じようにループを回して各オブジェクトの詳細クラスを作成します。 可毒性が高いのはやはりサンプル時にListをClearしてオブジェクトそれぞれの詳細クラスのインスタンスを生成し設定してリストに追加するだと思います。 しかし、ごみなどが出るのではないかと思い、すでにlistには前回分のオブジェクトの詳細リストがあるので先頭から範囲内(Indexが超えない範囲)は各変数の値の更新を行い、今回のサンプルの方がオブジェクトが多い場合は溢れる分は追加しようとしたい感じです。 1回目のサンプル「A,B,C,D,E」の詳細(クラス)がlistにある 2回目のサンプルでは「A,B,C,D」の詳細クラスの値を「C,D,G,H」の情報に上書き。 このままだと「E」の詳細クラスが残っているため削除したい。 といった感じですね。 ※ここでいう詳細クラスはオブジェクトの情報をもとに作り出されるいわば「表示用の値」をまとめたクラスのようなものです。
YAmaGNZ

2021/06/05 10:05

デバッグとしての用途ならClearしてアクティブなオブジェクトの詳細クラスを作成しつつAddするというシンプルな実装にしたほうがいいのではないかと思います。 それで問題が発生するのであれば、そこから改善すればいいのではないでしょうか。 「ゴミが出る」としきりに気にされていますが、ゴミとは何のことなのでしょうか? 解放されない詳細クラスをゴミと言われているのであれば、単純なClear→Addの実装より消し忘れが発生しそうな現在考えておられる実装のほうがゴミが残る可能性(バグを作りこむ可能性)が高いのではないでしょうか。
退会済みユーザー

退会済みユーザー

2021/06/05 10:21 編集

ゴミは「GC alloc」を指していました。 GCのコストについてもそれなりに考えているつもりでした。 プロファイラで確認したところ更新した方が速度も速くGC allocのサイズも小さかったので・・・。 ちょっと当初の質問とずれてしまいましたがありがとうございました!
guest

回答2

0

TestClassに更新されたフラグを追加すればかんたんになるかと思います。

(C#の標準の命名規約になおしています)

csharp

1using System.Linq; 2 3public class TestClass 4{ 5 public int Value; 6 public string Name; 7 public bool IsUpdated;// <- 更新時にtrueにする 8} 9 10 11void InitList() { 12 13 list = list.Where(e => e.IsUpdated).OrderBy(e => e.Value).ToList(); 14 foreach(var e in list) { 15 list.IsUpdated = false; 16 } 17}

別解

csharp

1using System.Linq; 2 3public class TestClass 4{ 5 public int Value; 6 public string Name; 7} 8List<TestClass> list = new List<TestClass>(); 9List<TestClass> updatedElements = new List<TestClass>(); 10 11 void InitList() 12 { 13 for (int i = 0; i < 100; i++) 14 { 15 TestClass t = new TestClass { value = i, name = i.ToString() }; 16 list.Add(t); 17 } 18 19 // リストの最初の50個を更新 20 int index; 21 for (index = 0; index < 50; index++) 22 { 23 UpdateList(index); 24 } 25 26 list = updatedElements.OrderBy(e => e.Value).ToList(); 27 updatedElement.Clear(); 28 } 29 30 void UpdateList(int index) 31 { 32 // 質問と同じ実装する 33 TestClass updatedElement = ...// 質問と同じ内容を実装し、更新された要素を保持 34 updatedElements.Add(updatedElement); 35 } 36

投稿2021/06/05 10:10

編集2021/06/05 10:30
takezoux2

総合スコア6

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

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

退会済みユーザー

退会済みユーザー

2021/06/05 10:20

ご回答ありがとうございます。 こちらは極端な話ですが1回目のサンプルで10万件見つかり、次のサンプルで10件しか見つからなかった場合、10万回ループを回して最初の10件の「IsUpdated」をtrueにしてそれ以外をFalseにする処理をするということでしょうか? 別でやり取りをしていてそちらの話を含めた返答となり面倒くさかったら無視で大丈夫です。
takezoux2

2021/06/05 10:24

void UpdateList(int index)メソッド内でIsUpdateをtrueにするだけなので、10件しか更新がなければ10回しかIsUpdateをtrueにする必要はありません。
退会済みユーザー

退会済みユーザー

2021/06/05 10:28

返答ありがとうございます。 例えばですが、10万件情報があり次のサンプルで5万件情報があった場合、5万件分だけIsUpdateをTrueにするということですよね。 そしてつぎのサンプルで10件しかなかった場合、10万件あるリストのうち前の2回で5万件ずつIsUpdateがTrueのものとFalseのものがあり、3回目のサンプルではすでにIsUpdateがTrueである49990件のIsUpdateをFalseにする処理が入るということでしょうか?
takezoux2

2021/06/05 10:31

はい、そうなります。また、別解も追記しました。 今どき10万件の処理ぐらいはそこまで気にする必要はありませんが、そのくらいのパフォーマンスを気になるなら別解のほうがパフォーマンスは良くなるかと思います。
YAmaGNZ

2021/06/06 03:38

別解は質問者さんが避けようとしている別Listを作るってことじゃないですか?
guest

0

検索するのが面倒というのであれば、こういう形でクラス自身に変更したかどうかの情報を持たせるのは?
でもって削除せずともlinqのWhereで絞り込めばいいだけだと思います
絞り込んだリストを次で使うって感じで
どうにも消費メモリがやばいのであれば絞り込む前のリストに絞り込んだリストを代入すれば参照は減るはず

c#

1public class TestClass 2{ 3 public bool HasChanged => IsValueChanged || IsNameChanged; 4 5 private int orgValue; 6 public int Value { get; set; } 7 public bool IsValueChanged => orgValue != Value; 8 9 private string orgName; 10 public string Name { get; set; } 11 public bool IsNameChanged => orgName != Name; 12 13 public TestClass(int val, string name) 14 { 15 Value = val; 16 orgValue = val; 17 Name = name; 18 orgName = name; 19 } 20 21 public void SetDefault() 22 { 23 orgValue = Value; 24 orgName = Name; 25 } 26}

投稿2021/06/06 03:29

len_souko

総合スコア1363

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問