0

私は単純なクラスを持っています:

public class RawBomItem
{
    private string material;
    private string item;
    private string component;
    private string quantity;
    private string b;
    private string spt;
...
}

すべてのデータメンバーにはプロパティがあります。

そして、このクラスのインスタンスを含むリストがあります

    private List<RawBomItem> rawBom;

リストには 70000 を超えるアイテムが含まれています。

この時点で、このリストに対して少し複雑な LINQ クエリを実行したいと思いました。

List<string> endProducts = new List<string>(
    rawBom.Where(x1 => new List<string>(rawBom.Select(x2 => x2.Component)
                                              .Distinct())
                           .Contains(x1.Material) && (x1.B != "F"))
          .Select(x3 => x3.Material));

クエリは無限ループに陥っているようです。(シャットダウンするまで数分待っていました)

私はそれをDBに変えて動作させます。何が問題なのかに興味があります。

4

4 に答える 4

9

無限ループがどのようにあるべきかわかりませんが、コードは非常に非効率的です。
アイテムごとrawBomに、コンポーネントの個別のセットを計算し、それらを新しいリストにコピーします。したがって、リストに70,000個のアイテムがある場合、70.000 ^ 2=4,900,000,000回の反復を実行します。さらに、リスト内のすべてのアイテムについて、個別のコンポーネントのリストをもう一度繰り返します。異なるコンポーネントの数に応じて、同じ回数の反復を上に追加します。

これは改善できます:

var components = new HashSet<string>(rawBom.Select(x => x.Component).Distinct());
var endProducts = rawBom.Where(x => components.Contains(x.Material) &&
                                    x.B != "F")
                        .Select(x => x.Material)
                        .ToList();
  1. メインクエリから個別のコンポーネントのリストの作成を抽出するため、70.000回ではなく、1回だけ計算する必要があります。
  2. HashSet<string>の代わりにを使用しList<string>ます。これにより、呼び出しがContainsからO(n)に変更されO(1)ます。

最終的には、リストを2回だけ列挙することになり、反復回数は140,000回になります。次に、それを元の反復回数と比較します。

于 2013-02-07T13:00:59.167 に答える
1

無限ループなのがちょっとリーチ。シーケンスがgeneratorでない限り、ここにはありません。

あなたが持っているのは、地獄のように非効率的なコードです。

rawBom.Where( // this goes over the 70,000 item collection once

これらの 70,000 のそれぞれについて、次のものがあります。

new List<string>(rawBom.Select(x2 => x2.Component).Distinct()) // this goes over the 70,000 collection 3 times (first select, then distinct, then new list)
.Contains // another bunch of accesses depending on how many distinct items there were
.Select(x3 => x3.Material) // iterates over the resulting collection once

だから遅くなるのは間違いない。

于 2013-02-07T13:04:45.500 に答える
0
List<RawBomItem> list = new List<RawBomItem>();
var components = list.Select(x => x.component).Distinct();
var b = new Func<RawBomItem, bool>(x =>
  {
    return components.Contains(x.Material) && x.B != "F";
  });
var v = list.Where(x => b(x)).Select(x1 => x1.material).ToList();
于 2013-02-07T13:07:19.613 に答える
0

クエリを少し単純化します。私はこれがあなたが望むものだと思いますか?

List<string> endProducts = rawBom
.Where(x1 => rawBom.Any(x2 => x2.Component == x1.Material) && x1.B != "2")
.Select(x1 => x1.Material).ToList();

これは、rawBom 内のすべてのアイテムに対して追加のリストを作成しませんが、それ自体を使用します

于 2013-02-07T13:03:27.930 に答える