Trouvez une combinaison de deux éléments qui n'ont pas été vus ensemble (LINQ, SQL ou C #)

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

Question

J'ai une page qui affiche deux objets, puis l'utilisateur en choisit un. J'enregistre la préférence et la combinaison dans une base de données MSSQL et stocke les données comme ceci:

UserId=1, BetterObjectId=1, WorseObjectId=2

Je voudrais maintenant éviter de montrer à nouveau cette combinaison d'objets (1,2 / 2,1).

Alors, comment générer des combinaisons aléatoires pour montrer à l'utilisateur les combinaisons exclues précédemment?

Cela semble être une question simple mais, comme la plupart des programmeurs, le manque de sommeil et de café me manque, votre aide est donc très appréciée: -)

L’approche très naïve ressemble à quelque chose de ce genre (et tous les appels à cette fonction devront être encapsulés dans un contrôle pour voir si l’utilisateur a déjà noté autant de fois que nCr où n est le nombre d'éléments et r est 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();
}

Modifications

À l'aide de SQL, je peux générer une liste de tous les éléments non complets (c'est-à-dire qu'il existe une combinaison associant l'élément que l'utilisateur n'a pas encore vu), mais je ne pense pas que ce soit particulièrement utile.

Je peux aussi imaginer générer toutes les combinaisons possibles et éliminer les vues déjà consultées avant de choisir 2 éléments aléatoires, mais il s’agit là d’une autre solution terrible.

Une possibilité (beaucoup de mémoire pour n grand) consiste à générer toutes les combinaisons possibles et à stocker la combinaison dans la notation. Ensuite, je peux simplement faire une sélection de toutes les combinaisons là où la combinaison n’est pas entrée (choisir la combinaison des cotes de l’utilisateur où ID utilisateur = x) avec quelques modifications reflétant la relation symétrique des combinaisons.

Était-ce utile?

La solution

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

Si vous avez besoin de cet ItemId1 < ItemId2 dans le tableau d'évaluation, il vous suffit de consulter le tableau d'évaluation une fois.

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

Voici un blog sur l'obtention de " random " traduit dans la base de données.

Autres conseils

Une solution est la suivante:

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

Je ne connaissais pas le < em> cross join méthode consistant à répertorier plusieurs tables FROM auparavant.

En supposant que la liste des éléments disponibles se trouve dans la base de données, je gérerais ce problème entièrement dans la base de données. Vous frappez déjà la base de données, peu importe quoi, alors pourquoi ne pas le faire là-bas?

Qu'en est-il de mettre tous les objets dans une file d'attente ou une pile, puis de supprimer 2 et 2 jusqu'à ce qu'ils soient vides?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top