A simple pseudo-random algorithm for choosing alternatives


In this post I want to talk about a simple proposal algorithm based on the choices made earlier. For this, first of all, we set two tasks:

  1. Select random value from array
  2. Select random value from array based on weight of values

Surely many will notice that to solve the first problem, there are ready-made functions in many PLs. However, I will come up with a bicycle to solve it differently, for a gradual approach to solving the second problem.

For the solution, I will use pseudocode somewhat similar to Javascript. Therefore, my random () method will return a value from 0 to 1.

So, task 1


You can simply iterate over the array in each iteration, getting randomly true / false, you can use the common Javascript solution of the form Math.floor(Math.random() * maxNumber), which, by the way, is an abridged version of the solution that I will use.

Decision


Divide the range of numbers from 0 to 1 into equal nsegments and take the nearest previous value from random:


Practical part

For simplicity, we take an array of 150 elements containing only our own indices. That is, a number series from 0 to 150.
maxNumber = 150; // максимальный индекс или длина массива
elementPart = 100 / maxNumber / 100; // процентная доля значения в массиве, в данном случае это 0.66%
randomResult = random();
cursor = 0;
for (i = 0; i <= maxNumber; i++) {
    cursor += elementPart;
    if (cursor >= randomResult) {
        result = i;
        break;
    }
}


Task 2


We introduce some initial data:
items = [ 
    {id: 1, score: 4},
    {id: 2, score: 0}, 
    {id: 3}
]

Where scoreis a certain quantity (number of points) that changes the “weight” of a value before other values. Points can be awarded for choosing a value or for the similarity of this value with a value selected once. The rules for scoring are limited only by imagination and the specific situation of application.
The attentive reader managed to notice that 0 points is not the default value. This is done in order to exclude the value from the selection, therefore, the default number of points will be taken as 1. To do this, we will correct the initial data:
for (i = 0; i < items.length; i++) {
    item = items[i];
    if (item.score === 0) {
        item.remove(); // убираем значение из массива
        continue;
    }
    if (item.score === null) {
        item.score = 1; // если score отсутствует, ставим по умолчанию 1
    }
}


Decision


The essence of the solution is to change the segments of values ​​in the range from 0 to 1.
Example:


Practical part

Add the weight calculation of the value:
sumScores = 0;
for (i = 0; i < items.length; i++) {  // считаем сумму всех очков
    sumScores += items[i].score;
}
for (i = 0; i < items.length; i++) {
    weight = items[i].score / sumScores;
    items[i].weight = weight;
}

Here, weight is a percentage of the total points of all elements.
We calculate the sum of weights and finalize the solution to problem 1:
sumWeights = 0
for (i = 0; i < items.length; i++) {  // считаем сумму всех весов
    sumWeights += items[i].weight;
}
cursor = 0;
for (i = 0; i < items.length; i++) {
    cursor += items[i].weight / sumWeights;
    if (cursor >= randomResult) {
        suggestedItem = items[i];
        break;
    }
}


Thus, we get a value with id = 1 with a higher probability than with id = 3. However, in this case, sooner or later we will come to the conclusion that the same values ​​will be offered (subject to an increase in the number of points and unless, of course, artificially exclude them from the sample).
Such a solution is quite applicable to systems where the user needs to offer something the most similar - we simply compose a score of the desired values ​​to your liking (the same color, the same type, maybe the same manufacturer) without forgetting to exclude the selected value by setting the score to 0 .
If you need a set, it is less likely to show similar products (for example, why would a person need a second vacuum cleaner if he just bought one?) Or offer to try something new without dropping the purchased goods from the selection (for example, ordering food or consumables ( the aroma of electronic cigarettes, etc.)), then you need to make small adjustments to the calculation of weights:
for (i = 0; i < items.length; i++) {
    weight = 1 - items[i].score / sumScore;
    if (items[i].score == sumScore) { 
        weight = 1;
    }
    items[i].weight = weight;
}

Where weight is the inverted value to the percentage.
In case we have only one item in the list that has a non-zero account, we check and assign 1 weight to this item.

Now, adding a point to the score every time the choice of this value is made, we move it further (while not excluding it from the selection), offering alternative options to the user.
These two approaches can be combined: for example, we offer the user a manufacturer whose products he usually purchases, but at the same time we offer goods that he has not yet purchased.

You can try the demo here.

On this topic


Read about the multi-criteria choice of alternatives and the rules of fuzzy choice here .

Also popular now: