一緒に表示されていない2つの要素(LINQ、SQL、またはC#)の組み合わせを見つける

StackOverflow https://stackoverflow.com/questions/601134

質問

2つのオブジェクトを表示するページがあり、ユーザーがこれらのオブジェクトの1つを選択します。設定と組み合わせをMSSQLデータベースに記録し、最終的に次のようなデータを保存します。

UserId=1, BetterObjectId=1, WorseObjectId=2

これで、オブジェクトの組み合わせ(1,2 / 2,1)が再び表示されるのを避けたいと思います。

では、ランダムに組み合わせを生成して、以前に表示した組み合わせを除外したユーザーを表示するにはどうすればよいですか?

これは本当に簡単な質問のように思えますが、ほとんどのプログラマーのように私は睡眠とコーヒーが不足しているので、あなたの助けは大歓迎です:-)

非常に単純なアプローチは次のようなものです(この関数へのすべての呼び出しは、ユーザーが既にnCr(nはアイテム数とrは2):

public List<Item> GetTwoRandomItems(int userId)
{
    Item i = null, i2 = null;
    List<Item> r = null;

    while (i == null || i2 == null)
    {
        r = GetTwoRandomItemsRaw();
        i = r[0];
        i2 = r[1];
        if (GetRating(i.Id, i2.Id, userId) != null) /* Checks if viewed */
        {
            i = null;
            i2 = null;
        }
    }
    return r;
}

private List<Item> GetTwoRandomItemsRaw()
{
    return Items.ToList().OrderBy(i => Guid.NewGuid()).Take(2).ToList();
}

編集

一部のSQLを使用して、完全ではないすべてのアイテムのリストを生成できます(つまり、ユーザーが見たことのないアイテムに関連する組み合わせがあります)が、特に役立つとは思いません。

2つのランダムなアイテムを選択する前に、考えられるすべての組み合わせを生成し、すでに表示されている組み合わせを削除することも想像できますが、これは別のひどい解決策です。

可能性(nが大きい場合にメモリを集中的に使用)は、可能なすべての組み合わせを生成し、combinationIdを評価に格納することです。その後、combinationIdが含まれていないすべての組み合わせのSELECTを実行できます(SELECTの組み合わせIDの評価WHERE userId = x)。組み合わせの対称関係を反映するようにいくつかの変更を加えます。

役に立ちましたか?

解決

Table Item: ItemId
Table Rating: UserId, ItemId1, ItemId2, WinnerId

ItemId1が必要な場合<!> lt;評価表のItemId2の場合、評価表を確認する必要があるのは1回だけです。

var pair = db.Items.Join(db.Items,
  i1 => i1.ItemId,
  i2 => i2.ItemId,
  (i1, i2) => new {i1, i2}
)  //produce all pairs
.Where(x => x.i1.ItemId < x.i2.ItemId) //filter diagonal to unique pairs
.Where(x => 
  !db.Ratings
  .Where(r => r.UserId == userId
    && r.ItemId1 == x.i1.ItemId
    && r.ItemId2 == x.i2.ItemId)
  .Any() //not any ratings for this user and pair
)
.OrderBy(x => db.GetNewId()) //in-database random ordering
.First();  // just give me the first one

return new List<Item>() {pair.i1, pair.i2 };

ブログ <!> quot; random <!> quot;の取得についてデータベースに変換されます。

他のヒント

1つの解決策は次のとおりです。

SELECT TOP 1 i.id item1, i2.id item2 from item i, item i2 
WHERE i.id <> i2.id 
AND (SELECT COUNT(*) FROM Rating WHERE userId=@userId AND FK_ItemBetter=i.id AND FK_ItemWorse=i2.id) = 0
AND (SELECT COUNT(*) FROM Rating WHERE userId=@userId AND FK_ItemBetter=i2.id AND FK_ItemWorse=i.id) = 0
ORDER BY NEWID()

< em>前に複数のFROMテーブルをリストするだけの方法 メソッド。

使用可能なアイテムのリストがデータベース内にあると仮定すると、この問題はデータベース内で完全に処理されます。何があってもすでにデータベースにアクセスしているので、そこでデータベースを取得してみませんか?

すべてのオブジェクトをキューまたはスタックに配置し、空になるまで2と2をポップするのはどうですか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top