Domanda

Ho una pagina che visualizza due oggetti e poi l'utente sceglie uno di questi.I record di preferenze e la combinazione di una base di dati di MSSQL e finire la memorizzazione di dati come questo:

UserId=1, BetterObjectId=1, WorseObjectId=2

Ora vorrei evitare di mostrare che la combinazione di oggetti (1,2 / 2,1), mai più.

Allora, come faccio a generare combinazioni casuali di mostrare all'utente escluso visualizzati in precedenza combinazioni?

Questo sembra come dovrebbe essere realmente una semplice domanda, ma come la maggior parte dei programmatori sono a corto di sonno e di caffè per il vostro aiuto è molto apprezzato :-)

Il molto approccio ingenuo è qualcosa di simile a questo (e di tutte le chiamate per questa funzione dovrebbe essere avvolto in un controllo per vedere se l'utente ha già votato come molte volte come nCr dove n è il numero di elementi e r a 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();
}

Modifiche

Utilizzando alcuni SQL è possibile generare un elenco di tutti gli elementi che non sono completi (cioèc'è una combinazione che coinvolge l'elemento che l'utente non ha visto), ma non credo sia particolarmente utile.

Posso anche immaginare che la generazione di tutte le combinazioni possibili ed eliminando già visto quelli prima di prendere il 2 elementi casuali, ma questo è un altro terribile soluzione.

Una possibilità (intensivo di memoria per n grande) è la generazione di tutte le combinazioni possibili e memorizzare il combinationId nella valutazione.Quindi posso solo fare una selezione di tutte le combinazioni in CUI combinationId NON È IN (SELECT combinationId DA valutazioni di CUI userId=x) con alcune modifiche per riflettere simmetrica rapporto di combinazioni.

È stato utile?

Soluzione

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

Se avete bisogno di ItemId1 < ItemId2 nella tabella di Valutazione, devi solo controllare la tabella di Valutazione di una volta.

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

Ecco un blog circa ottenere "casuale", tradotto in database.

Altri suggerimenti

Una soluzione è questa:

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

Non ero a conoscenza del cross join metodo di appena quotazione più DA tabelle prima.

Supponendo che l'elenco delle voci disponibili nel database, vorrei gestire completamente il problema nel database.Si stanno colpendo il database già, non importa cosa, quindi perché non farlo fare lì?

Cosa di mettere tutti gli oggetti in una coda o in una pila, e poi pop 2 e 2 off fino a quando sono vuote?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top