下記の「ソートするため更新しなかった残り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 }
示されたサンプルであればUpdateしたものだけ別のListにAddすればいいのではないかと思いますがそういうことではないんですよね?
情報が不足していて申し訳ございません。
Listは記載されているList1つだけという前提での話となります。
質問とそれてしまい記載しませんでしたが、気にしていることはゴミができるだけ発生しないこと、コピーが発生しないことも意識しています。
ですので最初は全追加ですが以降は範囲内は更新などをしています。
C#の知識はそこまでないのでいろいろなサイトで参考にしたことを個人的にやっているだけですが・・・。
例のソースを見たのですがよく分かりません。
UpdateListメソッドにてListにAddされたものも消すのですか?
Listを得た時点で削除するものが分かる(例で言えばインデックス50~)のであれば、最初に消せばUpdateListメソッドにてListにAddされたものは除外できるかと思います。
ただ質問する為に端折ったであろう仕様も実際には関係しそうに感じます。
例えばですが、現在アクティブ状態のオブジェクトが100こあったとします。
TestClassのインスタンスを生成し情報を設定し、リスト作成します。
Value順(例)にソートし表示するようにします。
次任意のタイミングでサンプルした際、アクティブなオブジェクトは50個でした。
その50個の情報を設定しリストを作成します。(事前に100要素あるのでリスト内0~49までの情報を更新)
value順のソートをしたいのですが残り50個は前の情報が入っており不要なので残りの50個をリストから削除したい。(ここの処理がもっとスマートに書けないものかと・・・)
ID順にソートして表示。
ListをClearして再度1つずつ情報クラスを生成して入れるのもいいのですが、ごみが発生したり更新する方が使いまわしで良いのかなと思っている次第です。
よろしくお願いします。
1.アクティブなオブジェクト100個のList作成
2.アクティブなオブジェクトが50個になった
3.1で作成したListから2の段階でアクティブではないオブジェクトを削除する
ということですか?
2でアクティブなオブジェクトというのは必ずListの先頭からX個という状態になるのですか?
そうなのであればRemoveRangeにてそれ以降を消すというのでいいかと思います。
100個のListから何かしらの条件で消すオブジェクトが連続しないのであればループ(使用できるならLinqもあり)しRemoveAtなりで消すしかないかと思います。
具体的な処理が分からないので「次任意のタイミングでサンプルした際、アクティブなオブジェクトは50個でした。」という時点でアクティブなオブジェクトのリストが出来ているのではないかとも思ってしまいます。
> ListをClearして再度1つずつ情報クラスを生成して入れるのもいいのですが、ごみが発生したり更新する方が使いまわしで良いのかなと思っている次第です。
その判断に至った理由は?
速度的にメチャクチャシビアで計測した結果それが最も現実的、とかいうのでなければ、わかりやすさ最優先で作ったほうがよっぽど良いと思うけども。
どうしてもその「オブジェクトを使い回す」という要件が必須というわけではない(実際にやってみて不都合がない)のであれば、より単純な方法で実装するべきでしょう。
別の手段で簡単に実現可能な事を、ロクな根拠もなく難しくするのは、バグを生むキッカケにしかならないので愚の骨頂。
>gentaroさん
>速度的にメチャクチャシビアで計測した結果それが最も現実的、とかいうのでなければ、わかりやすさ最優先で作ったほうがよっぽど良いと思うけども。
ごもっともだと思います。
>その判断に至った理由は?
こちらがデバッグ機能として使う場合を想定して書いているからとなります。
スマートフォン端末などのデバッグ機能として使用したい場合デバッグ機能の処理が激重でもっさりして見えるとかなると困るためできるだけゴミなどが出ない方法はないかなと思い試している最中となります。
他の方々も仰っているように、『仕様による』のではないかと思いますが。
>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」の詳細クラスが残っているため削除したい。
といった感じですね。
※ここでいう詳細クラスはオブジェクトの情報をもとに作り出されるいわば「表示用の値」をまとめたクラスのようなものです。
デバッグとしての用途ならClearしてアクティブなオブジェクトの詳細クラスを作成しつつAddするというシンプルな実装にしたほうがいいのではないかと思います。
それで問題が発生するのであれば、そこから改善すればいいのではないでしょうか。
「ゴミが出る」としきりに気にされていますが、ゴミとは何のことなのでしょうか?
解放されない詳細クラスをゴミと言われているのであれば、単純なClear→Addの実装より消し忘れが発生しそうな現在考えておられる実装のほうがゴミが残る可能性(バグを作りこむ可能性)が高いのではないでしょうか。
ゴミは「GC alloc」を指していました。
GCのコストについてもそれなりに考えているつもりでした。
プロファイラで確認したところ更新した方が速度も速くGC allocのサイズも小さかったので・・・。
ちょっと当初の質問とずれてしまいましたがありがとうございました!