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:
- Select random value from array
- 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
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 .