2

T-SQL ではCROSS APPLY、ステートメントの左右のテーブル間で考えられるすべてのバリエーションを取得するために使用できます。今、私は次のような状況にC#あり、LINQ-to-Objects を使用して問題を解決する方法があることを願っています。

TestDataオブジェクトに似たオブジェクト(以下のような)のリストがありKeyValuePair<string, object>ます(ちょうどaKeyValueプロパティ):キーはすべてにすることができ、同じキーを持つ複数のオブジェクトが存在する可能性があります。

IList<KeyValuePair<String, Object>> objects;
// Content of list
// # | Key  | Value
// 1 | "A"  | 1
// 2 | "A"  | 2
// 3 | "A"  | 3
// 4 | "B"  | 4
// 5 | "B"  | 5
// 6 | "C"  | 6
// 7 | "D"  | 7
// 8 | "D"  | 8

リクエストされたキーのリストもあります:

IList<String> requestedKeys = new List<string>() { "A", "D" };

ここで、リスト内のキー間の KeyValuePair オブジェクトのすべての可能な組み合わせを取得したいと考えていますrequestedKeys

IList<IList<KeyValuePair<String, Object>>> result = ...
// Content of 'result' will be in this example 6 lists with each 2 KeyValuePair objects
// #  | "A" | "D" | (If there are more in the requestedKey list then there are more KeyValuePair items in the innerlist.)
// 1  |  1  |  7  |
// 2  |  2  |  7  |
// 3  |  3  |  7  |
// 4  |  1  |  8  |
// 5  |  2  |  8  |
// 6  |  3  |  8  |

LINQ-to-Objects を使用して私の問題を解決することは可能ですか? そうでない場合は、とにかくそれを構築する最も効率的な方法を教えてください.


編集1:
結果がどうあるべきかをより明確にするために:
次のようなLINQ-to-Objectsクエリが必要です:
@ジョアンナは、複数のsに関するヒントに感謝しますfromが、問題は次のとおりです:この構文では、動的なsの量from。私の場合、リストfrom内のアイテムと同じ数の sが必要ですrequestedKeys

var result =    
   from listA in objects.Where(m => m.Key == "A")
   from listD in objects.Where(m => m.Key == "D")
   // from .....
   // from .....
   // overhere as many froms as items in 'requestedKeys' list   
select new [] { listA, listD /*, All other lists */ }
4

4 に答える 4

3

これらの行に沿った何かが機能するはずです:

var filtered = objects
        .Where(o => requestedKeys.Contains(o.Key));

var crossJoined = from el1 in filtered
                    from el2 in filtered
                    select new [] {el1, el2};

クロス結合は、複数のfrom句を連鎖させることによって実現されます。

編集:

この場合、編集で開始した方法よりも簡単な方法は考えられません。唯一欠けているのは、値を選択することです。

var result =    
   from listA in objects.Where(m => m.Key == "A").Select(m => m.Value)
   from listD in objects.Where(m => m.Key == "D").Select(m => m.Value)
   // from .....
   // from .....
   // overhere as many froms as items in 'requestedKeys' list  
select new [] { listA, listD /*, All other lists */ }
于 2012-05-22T16:54:19.527 に答える
1

私は自分で解決策を見つけました:

requestKeysリストの各アイテムには追加のクロス結合が必要なため、LINQでは非常に複雑な結合です。与えられた例のリストに関して、結果は次のようになりますobjects.Count(m => m.Key == "A") * objects.Count(m => m.Key == "D")(結果は3 * 2 = 6)。リスト内の余分な項目ごとに、結果セット全体がさらに乗算されます。

したがって、これが結果です。

// The result list
IEnumerable<IList<KeyValuePair<char, int>>> result;

// If there are no requestedKeys there is no result expected
if(requestedKeys.Count() > 0)
{
    // Loop through all request keys to cross join them together
    foreach (var key in requestedKeys)
    {
        if (result == null)
        {
            // First time the innerlist List<KeyValuePair<char, int>> will contain 1 item
            // Don't forget to use ToList() otherwise the expression will be executed to late.
            result = objects.Where(m => m.Key == key).Select(m => new List<KeyValuePair<char, int>>() { m }).ToList();
        }
        else
        {
            // Except for the first time the next subresult will be cross joined
            var subresult = objects.Where(m => m.Key == key).Select(m => new List<KeyValuePair<char, int>>() { m });
            result = result.Join(
                subresult,
                l1 => 0, // This and the next parameter does the cross join trick
                l2 => 0, // This and the previous parameter does the cross join trick
                (l1, l2) => l1.Concat(l2).ToList() // Concat both lists which causes previous list plus one new added item
                ).ToList(); // Again don't forget to 'materialize' (I don't know it is called materialization in LINQ-to-Objects 
                            // but it has simular behaviors because the expression needs to be executed right away)
        }
    }           
}
return result;

残念ながら、それは完全にLINQではないので、誰かがより良い解決策を知っている場合。私にコメントするか、私の質問に答えてください:)

于 2012-05-23T12:45:33.370 に答える
1

ユーザーはこの方法でSQLクロス適用を生成できます。

    var comments = AppCommentRepository.Where(com => com.iAction > -1 && productIds.Contains(com.sProductId))
            .GroupBy(c => c.sProductId)
            .SelectMany(p => p.OrderByDescending(cc => cc.dAddTime).Take(commentNum)).ToList();

最後に、SQLは次のとおりです。

    SELECT [t3].[iCommentId], .....FROM (
        SELECT [t0].[sProductId]
        FROM [dbo].[App_Comment] AS [t0]
        WHERE ([t0].[iAction] > -1) --AND ([t0].[sProductId] IN (@p1))
           GROUP BY [t0].[sProductId]
        ) AS [t1]
CROSS APPLY (
    SELECT TOP (2) [t2].[iCommentId],......
    FROM [dbo].[App_Comment] AS [t2]
    WHERE ([t1].[sProductId] = [t2].[sProductId]) AND ([t2].[iAction] > -1)
-- AND ([t2].sProductId] IN (@p1))
    ORDER BY [t2].[dAddTime] DESC
    ) AS [t3]
ORDER BY [t3].sProductId DESC
于 2014-01-15T09:54:44.467 に答える
0
objects
.Join(requestedKeys, o => o.Key, rk => rk, (o, rk) => o)
.SelectMany(o => requestedKeys.Select(k => new {Key = k, Value = o.Value}));
于 2016-11-12T16:38:48.917 に答える