2017-02-23 5 views
6

私は現在asp.netのWebアプリケーションで作業しています。特定のAPI呼び出しでは、ListAとListBのListBを比較して、ListAにListBのListの要素が同じかどうかを判断する必要があります。言い換えれば、ListAがListBに含まれている場合。リストを効率的に比較するには?

両方のコレクションは、EF-Code-First dbのLinqで照会されます。 ListBには、Listまたはnoneのいずれかに一致するものが1つあります。複数のものは決してありません。最悪の場合ListBには何百万もの要素があるので、比較はスケーラビリティが必要です。

ネストされたforeachループを実行する代わりに、私は純粋なlinqクエリを探しています。これは、dbに作業をさせます。構造を説明するために

(私はマルチカラムインデックスを検討する前に):そのEFデータベースので

//In reality Lists are queried of EF 
var ListA = new List<Element>(); 
var ListB = new List<List<Element>>(); 
List<Element> solution; 
bool flag = false; 
foreach (List e1 in ListB) { 
    foreach(Element e2 in ListA) { 
     if (e1.Any(e => e.id == e2.id)) flag = true; 
     else { 
      flag = false; 
      break; 
     } 
    } 
     if(flag) { 
      solution = e1; 
      break; 
     } 
} 

アップデート構造

を私は、関連するオブジェクトの構造を提供します。私は本当のコードを投稿することができるかどうか分からないので、この例はまだ一般的です。

//List B 
class Result { 
     ... 
     public int Id; 

     public virtual ICollection<Curve> curves; 

     ... 
} 

class Curve { 
     ... 
     public int Id; 

     public virtual Result result; 
     public int resultId; 

     public virtual ICollection<Point> points; 
     ... 
} 
public class Point{ 
    ... 
    public int Id; 
    ... 
} 

コントローラ(api-call用)は、正しいCurve-Objectを提供したいと考えています。正しいオブジェクトを識別するために、フィルタ(ListA)が提供されています(実際にはカーブオブジェクトです)。 フィルタ(ListA)を結果リスト(ListB)の曲線リストと比較する必要があります。 曲線は両方のポイントを比較することです。 (実際のリスト比較) 曲線には約1〜50点があります。 結果は約500,000,000になります。

すべてのオブジェクト(フィルタさえも)がdbを再クエリするため、Object-Identityで比較することができます。

このような状況を回避する方法ではなく、このメカニズムを実装する方法を探しています。

bool isIn = ListB.Any(x=>x.Count==ListA.Count && ListA.All(y=>x.Contains(y))); 

か、あなたが要素をしたい場合

はこれを試してみてください

class controller { 
    ... 
    public Response serveRequest(Curve filter) { 
     foreach(Curve c in db.Result.curves) { 
       if(compare(filter.points , c.points)) return c; 

     } 
    } 
} 
+0

あなたのコードはコンパイルされません。実際のコードを載せてください。 obs:それは 'var'です – Lucas

+0

内部結合を使用する必要がありますが、構造をよく知らずに、提案するのは難しいです。 – Dexion

+0

関連性はありますが、ここでEFに関する懸念があるため、詐欺ではありません:http://stackoverflow.com/questions/9524681/linq-compare-two-lists –

答えて

0
:(説明のために)

(マルチカラム・インデックスを(表を変更すること)を使用することによって)

var solution = ListB.FirstOrDefault(x=>x.Count==ListA.Count && ListA.All(y=>x.Contains(y))); 
2

使用Except:

public static bool ContainsAllItems(IList<T> listA, IList<T> listB) 
    { 
     return !listB.Except(listA).Any(); 
    } 

上記のメソッドはlistAにlistBのすべての要素が含まれているかどうかを示します。複雑さはO(n * m)アプローチよりもはるかに速いです。

+0

メモリ内の同じインスタンスを指している場合、これはうまくいきます。あるいは、IEqualityComparerを作成した場合 – Lucas

+2

しかし、これはどのようにSQLで動作しますか? –

0

私はあなたのために何かを持っている:EX-

var listALookup = listA.ToLookup(item => item.Id); 
var result = listB.FirstOrDefault(childList => childList.Count == listA.Count && childList.All(childListItem => listALookup.Contains(childListItem.Id))); 

Lookup.Containを比較する前に

var db = new MyContext(); 

var a = db.LoadList(); // or whatever 
var b = new List<IQueryable<Entities>>(db.LoadListOfLists()/*or whatever*/); 

b.Any(x => x.Count.Equals(a.Count) & x.All(y => a.Any(z => z.Id == y.Id))); 
0

パフォーマンスが問題なので、私はあなたのLISTAを変換することをお勧めは/辞書をルックアップするためには、O(1であります)whileリスト。O(n)

この比較をdbレベルで実行すると、不要なデータのロードを減らすことができます。

関連する問題