Finden sie eine Kombination aus zwei Elementen, die nicht zusammen gesehen haben (LINQ, SQL oder C #)

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

Frage

Ich habe eine Seite, die zwei Objekte anzeigt und dann der Benutzer wählt einen von diesen. Ich nehme den Vorzug und die Kombination in einer MSSQL-Datenbank und am Ende Daten wie folgt zu speichern:

UserId=1, BetterObjectId=1, WorseObjectId=2

Nun würde Ich mag diese Kombination von Objekten zu vermeiden, zeigt (1,2 / 2,1) immer wieder.

So wie ich zufällige Kombinationen erzeugen, um den Benutzer zu zeigen, ohne zuvor angezeigte Kombinationen?

Dies scheint, wie es eine wirklich einfache Frage sein sollte, aber wie die meisten Programmierer ich auf den Schlaf und Kaffee kurz bin so Ihre Hilfe sehr geschätzt wird: -)

Der sehr naive Ansatz ist so etwas wie diese (und alle Anrufe an diese Funktion in einem Scheck eingewickelt werden müssen, um zu sehen, ob der Benutzer bereits so oft wie nCr bewertet hat, wobei n die ist Elementanzahl und 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();
}

Edits

Mit etwas SQL ich eine Liste aller Elemente erzeugen kann, die nicht vollständig sind (das heißt, es ist eine Kombination der Artikel beteiligt, dass der Benutzer nicht gesehen hat), aber ich glaube nicht, ist besonders nützlich.

Ich kann sich auch vorstellen, jede mögliche Kombination und die Beseitigung bereits gesehen diejenigen Erzeugung vor 2 zufällige Elemente Kommissionierung aber das ist eine andere schreckliche Lösung.

Eine Möglichkeit (speicherintensiv für große n) alle möglichen Kombinationen zu erzeugen und die combinationId in der Bewertung zu speichern. Dann kann ich nur eine SELECT aller Kombinationen tun, wo combinationId IS NOT IN (SELECT combinationId FROM Bewertungen userid = x) mit einigen Änderungen die symmetrische Beziehung von Kombinationen zu reflektieren.

War es hilfreich?

Lösung

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

Wenn Sie verlangen, dass ItemId1

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 };

Hier ist ein Blog rel="nofollow über das erhalten "random" übersetzt in die Datenbank.

Andere Tipps

Eine Lösung ist dies:

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()

ich war nicht bewusst, die < em> Cross Join Verfahren kurz vor mehreren aus den Tabellen aufgeführt sind.

Unter der Annahme,

, dass die Liste der verfügbaren Elemente in der Datenbank ist, würde ich dieses Problem vollständig in der Datenbank handhaben. Sie schlagen die Datenbank bereits, egal was passiert, also warum es nicht da getan?

Was ist, alle Objekte in einer Warteschlange oder einem Stapel setzen, und dann Pop-2 und 2 ab, bis sie leer sind?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top