2016-03-28 2 views
0

私は、構造体の一般的な配列を取り、クエリおよび/またはorderbyを実行し、そして/または動的linqを使って式を文字列として取り、一致するインデックスのリストを返すフィルタメソッドを持っていますこれは外部プログラムによって使用されます。Dynamic Linqからのインデックスリスト返す

Iは、最初は単に次のようにアイテムは、フィルタリングされたリスト内の項目に等しかった元のリストおよび発見を反復することによって、インデックスリストを得るために粗いレディアプローチのビットを採用:

public static int[] FilterStructs<T>(IList<T> structs, string query = "", string orderBy = "", int topN = 0) where T : struct {    
     var filteredStructs = structs.AsQueryable(); 
     if (!string.IsNullOrEmpty(query)) filteredStructs = filteredStructs.Where(query); 
     if (!string.IsNullOrEmpty(orderBy)) filteredStructs = filteredStructs.OrderBy(orderBy); 
     if (topN > 0) filteredStructs = filteredStructs.Take(topN); 
     return GetArrayIndexList(structs, filteredStructs.ToArray()); 
    } 

    private static int[] GetArrayIndexList<T>(IList<T> arrMain, T[] arrFiltered) where T : struct { 
     List<int> indexes = new List<int>(); 
     for (int i = 0; i < arrFiltered.Length; i++) { 
      for (int j = 0; j < arrMain.Count; j++) { 
       if (arrMain[j].Equals(arrFiltered[i])) { 
        indexes.Add(j); 
        break; 
       } 
      } 
     } 
     return indexes.ToArray(); 
    } 

しかし、構造体の配列にも数千もの項目があると、これは非常に遅くなります。

私は理想的に何をしたいのですか?最初は動的select文を使用して、構造体の配列を追加の "index"フィールドを持つ新しい配列に投影し、フィルタリングを実行してから、 select文は簡単です。

しかし、私はこれをどのように達成できるかについて少し空白を描いています。

アドバイスありがとうございます。

答えて

0

私は予想エンティティ名が含まれるようにクエリとORDERBY句ごとの着信文字列式を変更する必要があるため、これは、私の理想的なソリューションではありませんが、私が思ったよりも簡単でした。しかし、それは動作しますので、私はもっと時間があるまでこれを行います。

public static int[] FilterStructs<T>(IList<T> structs, string query = "", string orderBy = "", int topN = 0) where T : struct { 
     var withIndex = structs.Select((s, i) => new { index = i, item = s }); 
     var filteredStructs = withIndex.AsQueryable(); 
     if (!string.IsNullOrEmpty(query)) filteredStructs = filteredStructs.Where(query); 
     if (!string.IsNullOrEmpty(orderBy)) filteredStructs = filteredStructs.OrderBy(orderBy); 
     if (topN > 0) filteredStructs = filteredStructs.Take(topN); 
     return filteredStructs.Select("index").Cast<int>().ToArray();    
    } 

たとえば、以前のwhere句が「値= 123」だった場合、「item.value = 123」になります。

+0

これに伴い、GetArrayIndexListメソッドを使用することによる実行時間が約1500msから40msに短縮されました。 – Hoodlum

0

フィルタリングされた配列要素が元の配列に存在することがわかっている場合は、GetArrayIndexList本文を次のように置き換えることができます。

private static int[] GetArrayIndexList<T>(IList<T> arrMain, T[] arrFiltered) where T : struct 
    { 
     return arrFiltered.Select(c=> arrMain.IndexOf(c)).ToArray(); 
    } 
+0

ありがとうございます。しかし、私はIndexOfがデフォルトの等価比較関数を使用すると考えています。これはメソッドを遅くする原因となっています。これはコードがはるかに少ないですが、4000個の項目を持つ配列の場合、1秒以上の時間がかかります。 – Hoodlum

関連する問題