0

添付したライブラリオブジェクトのリストから、情報オブジェクトの奥深くにデータを取得しようとしています。私が持っている2つの解決策は、どちらも非常に非効率的です。linqクエリをより長いバリアントにすることなく、これを単一のOfType呼び出しに減らす方法はありますか?

using System;
using System.Collections.Generic;
using System.Linq;

namespace LinqQueries
{

    // Test the linq queries
    public class Test
    {
        public void TestIt()
        {
            List<ThirdParty> As = new List<ThirdParty>();

            // This is nearly the query I want to run, find A and C where B 
            // and C match criteria
            var cData = from a in As
                        from b in a.myObjects.OfType<MyInfo>()
                        where b.someProp == 1
                        from c in b.cs
                        where c.data == 1
                        select new {a, c};

            // This treats A and B as the same object, which is what I
            // really want, but it calls two sub-queries under the hood, 
            // which seems less efficient 
            var cDataShorter = from a in As
                               from c in a.GetCs()
                               where a.GetMyProp() == 1
                               where c.data == 1
                               select new { a, c };
        }
    }

    // library class I can't change
    public class ThirdParty
    {
        // Generic list of objects I can put my info object in
        public List<Object> myObjects;
    }

    // my info class that I add to ThirdParty
    public class MyInfo
    {
        public List<C> cs;
        public int someProp;
    }

    // My extension method for A to simplify some things.
    static public class MyExtentionOfThirdPartyClass
    {
        // Get the first MyInfo in ThirdParty
        public static MyInfo GetB(this ThirdParty a)
        {
            return (from b in a.myObjects.OfType<MyInfo>()
                    select b).FirstOrDefault();
        }

        // more hidden linq to slow things down...
        public static int GetMyProp(this ThirdParty a)
        {
            return a.GetB().someProp;
        }

        // get the list of cs with hidden linq
        public static List<C> GetCs(this ThirdParty a)
        {
            return a.GetB().cs;
        }
    }

    // fairly generic object with data in it
    public class C
    {
        public int data;
    }
}
4

2 に答える 2

1

正しい結果が生成されていると言っている場合はcDataShorter、次のように書き直すことができます。

As.SelectMany(a => a.myObjects, (aa, mo) => new R {Tp = aa, Mi = mo as MyInfo})
  .Where(r => r.Mi != null && r.Mi.someProp == 1)
  //.Distinct(new Comparer<R>((r1, r2) => r1.Tp.Equals(r2.Tp))) 
  // If you need only one (first) MyInfo from a ThirdParty 
  // You don't need R if you're not going to use Distinct, just use an anonymous
  .SelectMany(r => r.Mi.cs, (rr, c) => new {a = rr.Tp, c})
  .Where(ao => ao.c.data == 1)      

public class R {
    public ThirdParty Tp;
    public MyInfo Mi;
}

簡単にするために、そこComparerから

于 2013-03-07T21:40:46.580 に答える
1

残念ながら、答えは「場合による」です。両方の方法でクエリを作成し、タイミングを実行する必要がありました。

1000 個のサード パーティ オブジェクト、それぞれ 1 個の MyObject、それぞれ 1000 個の c、すべての結果が基準に一致、最初のクエリは 2 倍高速です。条件に一致する MyObjects がない場合、クエリ 1 は 2 桁速くなります。ただし、複数の MyObjects がある場合、効率は逆になり、100 の ThirdParty、それぞれ 100 個の MyObjects、それぞれ 100 個の C で、すべての結果が一致し、2 番目のクエリは最初のクエリよりも 2 桁速くなります。MyObjects の一致はありません。最初のものは再び速くなります。

私は実際に遅いソリューションを実装することになりました。これは、コードがよりクリーンになり、遅いクエリのパフォーマンスがそれほど悪くなかったからです。

于 2013-04-18T15:14:20.093 に答える