Я работаю над тем, «как получить доступ к элементам случайным образом из массива в javascript». Я нашел много ссылок по этому поводу. Нравится: получить случайный элемент из массива JavaScript
var item = items[Math.floor(Math.random()*items.length)];
Но в этом случае мы можем выбрать только один элемент из массива. Если нам нужно более одного элемента, как мы можем этого добиться? Как мы можем получить более одного элемента из массива?
javascript
jquery
html
arrays
Шьям Диксит
источник
источник
Ответы:
Попробуйте эту неразрушающую (и быструю ) функцию:
function getRandom(arr, n) { var result = new Array(n), len = arr.length, taken = new Array(len); if (n > len) throw new RangeError("getRandom: more elements taken than available"); while (n--) { var x = Math.floor(Math.random() * len); result[n] = arr[x in taken ? taken[x] : x]; taken[x] = --len in taken ? taken[len] : len; } return result; }
источник
Set
(который не был доступен в 13: - /)Всего две строчки:
// Shuffle array const shuffled = array.sort(() => 0.5 - Math.random()); // Get sub-array of first n elements after shuffled let selected = shuffled.slice(0, n);
ДЕМО :
источник
let random = array.sort(() => .5 - Math.random()).slice(0,n)
Здесь есть однострочное уникальное решение
array.sort(() => Math.random() - Math.random()).slice(0, n)
источник
Портирование
.sample
из стандартной библиотеки Python:function sample(population, k){ /* Chooses k unique random elements from a population sequence or set. Returns a new list containing elements from the population while leaving the original population unchanged. The resulting list is in selection order so that all sub-slices will also be valid random samples. This allows raffle winners (the sample) to be partitioned into grand prize and second place winners (the subslices). Members of the population need not be hashable or unique. If the population contains repeats, then each occurrence is a possible selection in the sample. To choose a sample in a range of integers, use range as an argument. This is especially fast and space efficient for sampling from a large population: sample(range(10000000), 60) Sampling without replacement entails tracking either potential selections (the pool) in a list or previous selections in a set. When the number of selections is small compared to the population, then tracking selections is efficient, requiring only a small set and an occasional reselection. For a larger number of selections, the pool tracking method is preferred since the list takes less space than the set and it doesn't suffer from frequent reselections. */ if(!Array.isArray(population)) throw new TypeError("Population must be an array."); var n = population.length; if(k < 0 || k > n) throw new RangeError("Sample larger than population or is negative"); var result = new Array(k); var setsize = 21; // size of a small set minus size of an empty list if(k > 5) setsize += Math.pow(4, Math.ceil(Math.log(k * 3, 4))) if(n <= setsize){ // An n-length list is smaller than a k-length set var pool = population.slice(); for(var i = 0; i < k; i++){ // invariant: non-selected at [0,n-i) var j = Math.random() * (n - i) | 0; result[i] = pool[j]; pool[j] = pool[n - i - 1]; // move non-selected item into vacancy } }else{ var selected = new Set(); for(var i = 0; i < k; i++){ var j = Math.random() * n | 0; while(selected.has(j)){ j = Math.random() * n | 0; } selected.add(j); result[i] = population[j]; } } return result; }
Реализация перенесена из Lib / random.py .
Примечания:
setsize
устанавливается на основе характеристик в Python для повышения эффективности. Хотя он не был адаптирован для JavaScript, алгоритм по-прежнему будет работать, как ожидалось.Array.prototype.sort
. Однако этот алгоритм гарантированно завершится через конечное время.Set
реализованы, набор можно заменить наArray
и.has(j)
заменить на.indexOf(j) > -1
.Производительность против принятого ответа:
источник
Получение 5 случайных элементов без изменения исходного массива:
const n = 5; const sample = items .map(x => ({ x, r: Math.random() })) .sort((a, b) => a.r - b.r) .map(a => a.x) .slice(0, n);
(Не используйте это для больших списков)
источник
создать функцию, которая делает это:
var getMeRandomElements = function(sourceArray, neededElements) { var result = []; for (var i = 0; i < neededElements; i++) { result.push(sourceArray[Math.floor(Math.random()*sourceArray.length)]); } return result; }
вы также должны проверить, достаточно ли элементов в sourceArray для возврата. и если вы хотите, чтобы возвращались уникальные элементы, вы должны удалить выбранный элемент из sourceArray.
источник
sourceArray
несколько раз.Синтаксис ES6
const pickRandom = (arr,count) => { let _arr = [...arr]; return[...Array(count)].map( ()=> _arr.splice(Math.floor(Math.random() * _arr.length), 1)[0] ); }
источник
Если вы хотите случайным образом получать элементы из массива в цикле без повторений, вы можете удалить выбранный элемент из массива с помощью
splice
:var items = [1, 2, 3, 4, 5]; var newItems = []; for (var i = 0; i < 3; i++) { var idx = Math.floor(Math.random() * items.length); newItems.push(items[idx]); items.splice(idx, 1); } console.log(newItems);
источник
1
являетсяdeleteCount
указание количества старых элементов массива , чтобы удалить. (Кстати, последние две строчки я сократил доnewItems.push(items.splice(idx, 1)[0])
).Array.prototype.getnkill = function() { var a = Math.floor(Math.random()*this.length); var dead = this[a]; this.splice(a,1); return dead; } //.getnkill() removes element in the array //so if you like you can keep a copy of the array first: //var original= items.slice(0); var item = items.getnkill(); var anotheritem = items.getnkill();
источник
Вот хорошо напечатанная версия. Это не подводит. Возвращает перемешанный массив, если размер выборки превышает длину исходного массива.
function sampleArr<T>(arr: T[], size: number): T[] { const setOfIndexes = new Set<number>(); while (setOfIndexes.size < size && setOfIndexes.size < arr.length) { setOfIndexes.add(randomIntFromInterval(0, arr.length - 1)); } return Array.from(setOfIndexes.values()).map(i => arr[i]); } const randomIntFromInterval = (min: number, max: number): number => Math.floor(Math.random() * (max - min + 1) + min);
источник
lodash ( https://lodash.com/ )
_.sample
и_.sampleSize
.Получает один или n случайных элементов с уникальными ключами из коллекции до размера коллекции.
_.sample([1, 2, 3, 4]); // => 2 _.sampleSize([1, 2, 3], 2); // => [3, 1] _.sampleSize([1, 2, 3], 4); // => [2, 3, 1]
источник
_
? Это не стандартный объект Javascript.РЕДАКТИРОВАТЬ : это решение работает медленнее, чем другие, представленные здесь (которые объединяют исходный массив), если вы хотите получить только несколько элементов. Скорость этого решения зависит только от количества элементов в исходном массиве, в то время как скорость решения для склейки зависит от количества элементов, требуемых в выходном массиве.
Если вам нужны не повторяющиеся случайные элементы, вы можете перетасовать свой массив, а затем получить столько, сколько хотите:
function shuffle(array) { var counter = array.length, temp, index; // While there are elements in the array while (counter--) { // Pick a random index index = (Math.random() * counter) | 0; // And swap the last element with it temp = array[counter]; array[counter] = array[index]; array[index] = temp; } return array; } var arr = [0,1,2,3,4,5,7,8,9]; var randoms = shuffle(arr.slice(0)); // array is cloned so it won't be destroyed randoms.length = 4; // get 4 random elements
ДЕМО: http://jsbin.com/UHUHuqi/1/edit
Функция перемешивания взята отсюда: https://stackoverflow.com/a/6274398/1669279
источник
O(n+k)
(n элементов в массиве, вы хотите k из них), хотяO(k)
это возможно (и оптимально).O(2n)
что можно было бы сократить,O(n+k)
если бы вы изменили циклwhile (counter-- > len-k)
и извлекли из него последние (вместо первых)k
элементы. На самом делеsplice(i, 1)
нетO(1)
, ноO(k)
решение все еще возможно (см. Мой ответ). Однако сложность пространства,O(n+k)
к сожалению, остается неизменной, но можетO(2k)
зависеть от реализации разреженного массива.Мне нужна была функция для решения этой проблемы, поэтому я поделюсь ею здесь.
const getRandomItem = function(arr) { return arr[Math.floor(Math.random() * arr.length)]; } // original array let arr = [4, 3, 1, 6, 9, 8, 5]; // number of random elements to get from arr let n = 4; let count = 0; // new array to push random item in let randomItems = [] do { let item = getRandomItem(arr); randomItems.push(item); // update the original array and remove the recently pushed item arr.splice(arr.indexOf(item), 1); count++; } while(count < n); console.log(randomItems); console.log(arr);
Примечание: если
n = arr.length
тогда в основном вы перетасовываете массивarr
иrandomItems
возвращает этот перемешанный массив.Демо
источник
В этом ответе я хочу поделиться с вами тестом, который мне нужен, чтобы знать лучший метод, который дает равные шансы для всех элементов иметь случайный подмассив.
Метод 01
array.sort(() => Math.random() - Math.random()).slice(0, n)
используя этот метод, некоторые элементы имеют более высокие шансы по сравнению с другими.
calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { let occ = 0 for (let index = 0; index < iterations; index++) { const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize] /** Wrong Method */ const arr = myArray.sort(function() { return val= .5 - Math.random(); }); if(arr[0]===number) { occ ++ } } console.log("Probability of ",number, " = ",occ*100 /iterations,"%") } calculateProbability(0) calculateProbability(0) calculateProbability(0) calculateProbability(50) calculateProbability(50) calculateProbability(50) calculateProbability(25) calculateProbability(25) calculateProbability(25)
Способ 2
Используя этот метод, элементы имеют одинаковую вероятность:
const arr = myArray .map((a) => ({sort: Math.random(), value: a})) .sort((a, b) => a.sort - b.sort) .map((a) => a.value)
calculateProbability = function(number=0 ,iterations=10000,arraySize=100) { let occ = 0 for (let index = 0; index < iterations; index++) { const myArray= Array.from(Array(arraySize).keys()) //=> [0, 1, 2, 3, 4, ... arraySize] /** Correct Method */ const arr = myArray .map((a) => ({sort: Math.random(), value: a})) .sort((a, b) => a.sort - b.sort) .map((a) => a.value) if(arr[0]===number) { occ ++ } } console.log("Probability of ",number, " = ",occ*100 /iterations,"%") } calculateProbability(0) calculateProbability(0) calculateProbability(0) calculateProbability(50) calculateProbability(50) calculateProbability(50) calculateProbability(25) calculateProbability(25) calculateProbability(25)
Правильный ответ размещен по следующей ссылке: https://stackoverflow.com/a/46545530/3811640
источник
Вот оптимизированная версия кода, перенесенная из Python @Derek, с добавленной деструктивной (на месте) опцией, которая делает его самым быстрым из возможных алгоритмов, если вы можете с ним пойти. В противном случае он либо делает полную копию, либо, для небольшого количества элементов, запрошенных из большого массива, переключается на алгоритм, основанный на выборе.
// Chooses k unique random elements from pool. function sample(pool, k, destructive) { var n = pool.length; if (k < 0 || k > n) throw new RangeError("Sample larger than population or is negative"); if (destructive || n <= (k <= 5 ? 21 : 21 + Math.pow(4, Math.ceil(Math.log(k*3, 4))))) { if (!destructive) pool = Array.prototype.slice.call(pool); for (var i = 0; i < k; i++) { // invariant: non-selected at [i,n) var j = i + Math.random() * (n - i) | 0; var x = pool[i]; pool[i] = pool[j]; pool[j] = x; } pool.length = k; // truncate return pool; } else { var selected = new Set(); while (selected.add(Math.random() * n | 0).size < k) {} return Array.prototype.map.call(selected, i => population[i]); } }
По сравнению с реализацией Дерека, первый алгоритм намного быстрее в Firefox, но немного медленнее в Chrome, хотя теперь у него есть деструктивный вариант - самый производительный. Второй алгоритм просто на 5-15% быстрее. Я стараюсь не называть конкретных цифр, поскольку они различаются в зависимости от k и n и, вероятно, ничего не значат в будущем с новыми версиями браузеров.
Эвристика, которая делает выбор между алгоритмами, исходит из кода Python. Я оставил его как есть, хотя иногда выбирает более медленный. Он должен быть оптимизирован для JS, но это сложная задача, поскольку производительность угловых случаев зависит от браузера и их версии. Например, когда вы пытаетесь выбрать 20 из 1000 или 1050, он переключится на первый или второй алгоритм соответственно. В этом случае первый работает в 2 раза быстрее, чем второй в Chrome 80, но в 3 раза медленнее в Firefox 74.
источник
log(k*3, 4)
поскольку в JS нетbase
аргумента. Должно бытьlog(k*3)/log(4)
pool
в качествеresult
. Поскольку вы усекаете,pool
его нельзя больше использовать в качестве источника для выборки, и в следующий раз, когдаsample
вы будете использовать его, вам придется снова воссоздатьpool
из какого-то источника. Реализация Дерека только перемешивает пул, так что его можно идеально повторно использовать для выборки без повторного создания. И я считаю, что это наиболее частый вариант использования.Неразрушающий
функциональный стиль программирования 2020 , работающий в неизменном контексте.
const _randomslice = (ar, size) => { let new_ar = [...ar]; new_ar.splice(Math.floor(Math.random()*ar.length),1); return ar.length <= (size+1) ? new_ar : _randomslice(new_ar, size); } console.log(_randomslice([1,2,3,4,5],2));
источник
_shuffle
функция?Он извлекает случайные элементы из srcArray один за другим, пока этого достаточно или в srcArray больше не осталось элементов для извлечения. Быстро и надежно.
function getNRandomValuesFromArray(srcArr, n) { // making copy to do not affect original srcArray srcArr = srcArr.slice(); resultArr = []; // while srcArray isn't empty AND we didn't enough random elements while (srcArr.length && resultArr.length < n) { // remove one element from random position and add this element to the result array resultArr = resultArr.concat( // merge arrays srcArr.splice( // extract one random element Math.floor(Math.random() * srcArr.length), 1 ) ); } return resultArr; }
источник
2019 г.
Это то же самое, что и ответ Лауринаса Малишаускаса , только элементы уникальны (без дубликатов).
var getMeRandomElements = function(sourceArray, neededElements) { var result = []; for (var i = 0; i < neededElements; i++) { var index = Math.floor(Math.random() * sourceArray.length); result.push(sourceArray[index]); sourceArray.splice(index, 1); } return result; }
Теперь, чтобы ответить на исходный вопрос «Как получить несколько случайных элементов с помощью jQuery», вот что:
var getMeRandomElements = function(sourceArray, neededElements) { var result = []; for (var i = 0; i < neededElements; i++) { var index = Math.floor(Math.random() * sourceArray.length); result.push(sourceArray[index]); sourceArray.splice(index, 1); } return result; } var $set = $('.someClass');// <<<<< change this please var allIndexes = []; for(var i = 0; i < $set.length; ++i) { allIndexes.push(i); } var totalRandom = 4;// <<<<< change this please var randomIndexes = getMeRandomElements(allIndexes, totalRandom); var $randomElements = null; for(var i = 0; i < randomIndexes.length; ++i) { var randomIndex = randomIndexes[i]; if($randomElements === null) { $randomElements = $set.eq(randomIndex); } else { $randomElements.add($set.eq(randomIndex)); } } // $randomElements is ready $randomElements.css('backgroundColor', 'red');
источник
Вот функция, которую я использую, которая позволяет вам легко выбирать массив с заменой или без нее:
// Returns a random sample (either with or without replacement) from an array const randomSample = (arr, k, withReplacement = false) => { let sample; if (withReplacement === true) { // sample with replacement sample = Array.from({length: k}, () => arr[Math.floor(Math.random() * arr.length)]); } else { // sample without replacement if (k > arr.length) { throw new RangeError('Sample size must be less than or equal to array length when sampling without replacement.') } sample = arr.map(a => [a, Math.random()]).sort((a, b) => { return a[1] < b[1] ? -1 : 1;}).slice(0, k).map(a => a[0]); }; return sample; };
Использовать его просто:
Без замены (поведение по умолчанию)
randomSample([1, 2, 3], 2)
может вернуться[2, 1]
С заменой
randomSample([1, 2, 3, 4, 5, 6], 4)
может вернуться[2, 3, 3, 2]
источник
var getRandomElements = function(sourceArray, requiredLength) { var result = []; while(result.length<requiredLength){ random = Math.floor(Math.random()*sourceArray.length); if(result.indexOf(sourceArray[random])==-1){ result.push(sourceArray[random]); } } return result; }
источник
Не могу поверить, что никто не упомянул этот метод, довольно чистый и простой.
const getRnd = (a, n) => new Array(n).fill(null).map(() => a[Math.floor(Math.random() * a.length)]);
источник
Вот самый правильный ответ, и он даст вам случайные + уникальные элементы.
function randomize(array, n) { var final = []; array = array.filter(function(elem, index, self) { return index == self.indexOf(elem); }).sort(function() { return 0.5 - Math.random() }); var len = array.length, n = n > len ? len : n; for(var i = 0; i < n; i ++) { final[i] = array[i]; } return final; } // randomize([1,2,3,4,5,3,2], 4); // Result: [1, 2, 3, 5] // Something like this
источник
items.sort (() => (Math.random ()> 0,5? 1: -1)). slice (0, количество);
источник