質問
私には二つのコレクション、それぞれ約40,000ます。
の要素がリストの2つの要素のリストを介して外す。
各要素のリストについて、に対応する要素のリスト。
のようなこと:
foreach(var item in list1)
{
var match = list2.Where(child => child.ID == item.ChildID).FirstOrDefault();
item.Child = match;
}
この作品にも影響を調べたもので、結果は、地獄である。
現在、list1とリストの2つのことに分けられているので、これらのキーからデータベースです。でlist1するなどの手段により、ChildIDとlist2するなどの手段により、IDと同じ値)となります。
と思い、バイナリ検索が飛躍的に高速度で読んだのどこかにそのLinqが選べるのに最適な戦略の一覧の場を提供しています。もっ明示的にキャストをソートされたリスト?たのかを実装する必要があるとカスタムバイナリ検索アルゴリズムw/a comparer?
意見ありがたくお受けいたします。.
感謝。
解決
なぜ使いに参加しませんか?
var query =
from a in list1
join b in list2 on a.ChildID equals b.ID
select new {Item1 = a, Item2 = b};
foreach(var item in query)
{
item.Item1.Child = item.Item2;
}
他のヒント
これは何について:
var joined = list1.Join(list2, x => x.ChildID, x => x.ID, (x, y) => new { x, y });
foreach (var j in joined)
{
j.x.Child = j.y;
}
私はこの問題を前に、LINQベースの検索は極めて少なくと比較しDBに基づくので活用していな。
ご採用を検討 辞書 わけです。
実践できる辞書およびその代わりに、利用できる ContainsKey とィールドが存在する場合、この値を使用 indexのアクセス用メソッド.
サンプルコード:
Dictionary<int, Child> list2 = ...;
...
foreach(var item in list1)
{
if (list2.ContainsKey(item.ChildID))
item.Child = list2[item.ChildID];
}
アクセス指数が大幅に高速検索のリストは、費用のメモリを要する。
を並列にそれらを介して、両方のリストが同じ値でソートされているので、あなたができるだけのループます:
int index1 = 0, index2 = 0;
while (index1 < list1.Count && index2 < list2.Count) {
while (index1 < list1.Count && list1[index1].ChildId < list2[index2].Id) index1++;
if (index1 < list1.Count) {
while (index2 < list2.Count && list2[index2].Id < list1[index1].ChildId) index2++;
if (index2 < list2.Count && list1[index1].ChildId == list2[index2].Id) {
list1[index].Child = list2[index2];
index1++;
index2++;
}
}
}
または
int index1 = 0, index2 = 0;
while (index1 < list1.Count && index2 < list2.Count) {
if (list1[index1].ChildId == list2[index2].Id) {
list1[index].Child = list2[index2];
index1++;
index2++;
} else {
if (list1[index1].ChildId < list2[index2].Id) {
index1++;
} else {
index2++;
}
}
}
別の効率的な代替手段は、しかし、リストの順番を利用しない、辞書にリストのいずれかを置くことによって、インデックスを作成することです。
Dictionary<int, TypeOfChild> index = new Dictionary<int, TypeOfChild>();
foreach (TypeOfChild child in list2) {
index.Add(child.Id, child);
}
foreach (TypeOfParent parent in list1) {
TypeOfChild child;
if (index.TryGetValue(parent.ChildId, out child) {
parent.Child = child;
}
}
私はこれに答えるために抵抗することができませんでした: - )
あなたのコードが遅くなる主な理由は、あなたのアイテムが多く、何度もreadedされるということです。スピードの技術である:あなたがする必要があり、あなたはそれを読むために必要がある場合は、可能な限り少ないとしてそれを読んでいる場合にのみメモリを読む
ここでは一例であります:
コード
public class Item
{
private int _id;
private List<ItemDetails> _detailItems = new List<ItemDetails>();
public Item(int id)<br>
{
_id = id;
}
public void AddItemDetail(ItemDetails itemDetail)
{
_detailItems.Add(itemDetail);
}
public int Id
{
get { return _id; }
}
public ReadOnlyCollection<ItemDetails> DetailItems
{
get { return _detailItems.AsReadOnly(); }
}
}
public class ItemDetails
{
private int _parentId;
public ItemDetails(int parentId)
{
_parentId = parentId;
}
public int ParentId
{
get { return _parentId; }
}
}
サンプルコード:
主な目標は、リストをスキャンし、現在のインデックスの項目とitemdetailを比較することです。 ParentIDは、その親IDに等しい場合。リストに追加し、次の詳細に進みます。それが異なる場合は、次の親に進みます。
// for performance tests..
DateTime startDateTime;
// create 2 lists (master/child list)
List<Item> itemList = new List<Item>();
List<ItemDetails> itemDetailList = new List<ItemDetails>();
Debug.WriteLine("# Adding items");
startDateTime = DateTime.Now;
// add items (sorted)
for (int i = 0; i < 400000; i++)
itemList.Add(new Item(i));
// show how long it took
Debug.WriteLine("Total milliseconds: " + (DateTime.Now - startDateTime).TotalMilliseconds.ToString("0") + "ms" );
// adding some random details (also sorted)
Debug.WriteLine("# Adding itemdetails");
Random rnd = new Random(DateTime.Now.Millisecond);
startDateTime = DateTime.Now;
int index = 0;
for (int i = 0; i < 800000; i++)
{
// when the random number is bigger than 2, index will be increased by 1
index += rnd.Next(5) > 2 ? 1 : 0;
itemDetailList.Add(new ItemDetails(index));
}
Debug.WriteLine("Total milliseconds: " + (DateTime.Now - startDateTime).TotalMilliseconds.ToString("0") + "ms");
// show how many items the lists contains
Debug.WriteLine("ItemList Count: " + itemList.Count());
Debug.WriteLine("ItemDetailList Count: " + itemDetailList.Count());
// matching items
Debug.WriteLine("# Matching items");
startDateTime = DateTime.Now;
int itemIndex = 0;
int itemDetailIndex = 0;
int itemMaxIndex = itemList.Count;
int itemDetailMaxIndex = itemDetailList.Count;
// while we didn't reach any end of the lists, continue...
while ((itemIndex < itemMaxIndex) && (itemDetailIndex < itemDetailMaxIndex))
{
// if the detail.parentid matches the item.id. add it to the list.
if (itemList[itemIndex].Id == itemDetailList[itemDetailIndex].ParentId)
{
itemList[itemIndex].AddItemDetail(itemDetailList[itemDetailIndex]);
// increase the detail index.
itemDetailIndex++;
}
else
// the detail.parentid didn't matches the item.id so check the next 1
itemIndex++;
}
Debug.WriteLine("Total milliseconds: " + (DateTime.Now - startDateTime).TotalMilliseconds.ToString("0") + "ms");
結果
私はより良い結果を見るために10倍以上のアイテムを取っます:
:
の項目を追加します
合計(ミリ秒):140msのの
itemdetailsを追加します。
合計(ミリ秒):203msの
ITEMLIST数:400000
を
ItemDetailList数:800000
を
一致する項目:
合計(ミリ秒):265ms
このは、高速タイプされたとクリーンである可能性があります。だから私は、あなたがそれを読むことができると思います。それを再生します。
Greetz、 イェルーンます。
このわかりません
item.Child = list2.FirstOrDefault(child => child.ID == item.ChildID)
これは暗黙のうちにちょうどどこに()を呼び出す可能性があるので、それは実際に助けないかもしれません。
ここで疑問がしかしだ、方法、実際に遅いですかそれは、コンパイル後に実行され、初回のみ遅いのですか?この上で議論チェックアウトに投稿します。