JavaScript: Случайные элементы массива

Родилось из C#-овой, но на JavaScript наглядней.

Нужно выбрать из массива N случайных элементов. Как это сделать быстро?

Если длина массива <= N — это очевидно. А если нет? Сначала склонируем массив:

Object.prototype.clone = function() {
var newObj = (this instanceof Array) ? [] : {};
for (i in this) {
  if (i == 'clone') continue;
  newObj[i] = (this[i] && typeof this[i] == "object") ? this[i].clone() : this[i];
  return newObj;
};

Потом создадим новый массив и скопируем в него нужное число элементов, а из оригинала удалим:

function selectRemoveAdd(arr, max)
{
 var arrLength = arr.length;
 if(max >= arrLength)
  return arr.clone();
 var newArray = [];
 var cloneArray = arr.clone();
 var i = 0, newPos = 0;
 while(i++ < max)
 {
  newPos = getRandom(arrLength);
  newArray.push(cloneArray[newPos]);
  cloneArray.splice(newPos, 1);
  arrLength--;
 }
 return newArray;
}

Такой вариант обычно предлагают на форумах. Но зачем создавать ещё одни массив? Можно взять исходный и удалить всё лишнее:

var arrLength = arr.length;
 if(max >= arrLength)
  return arr.clone();
 var newArray = arr.clone();
 while(arrLength-- > max)
  newArray.splice(getRandom(arrLength), 1);
 return newArray;

Какой вариант быстрее? Правильный ответ, что быстрее оба, но по-разному. Если N меньше arr.length / 2, то первый, если больше — то второй. Поэтому самый красивый и правильный способ — это:

function selectRemoveOnly(arr, max)
{
 var arrLength = arr.length;
 var newArray = arr.clone();
 while(arrLength-- > max)
   newArray.splice(getRandom(arrLength), 1);
 return newArray;
}
function selectRemoveAdd(arr, max)
{
 var arrLength = arr.length;
 var newArray = [];
 var cloneArray = arr.clone();
 var i = 0, newPos = 0;
 while(i++ < max)
 {
  newPos = getRandom(arrLength);
  newArray.push(cloneArray[newPos]);
  cloneArray.splice(newPos, 1);
  arrLength--;
 }
 return newArray;
}
function selectOptimised(arr, max)
{
 if(max >= arr.Length)
  return arr.clone();
 if(max <= arr.length / 2)
  return selectRemoveAdd(arr, max);
 else
  return selectRemoveOnly(arr, max);
}

И работать будет просто замечательно:

JavaScript: Объекты и необъекты

Говорят, во всём семействе ECMAScript все переменные — псевдообъекты.

Так вот, это неправда.

В JavaScript, например, всего 6 типов объектов:

null, unde­fined, num­ber, string, boolean и object

а значит, записать в числовую переменную новое свойство — нельзя.

Вызывая оператор “.” для num­ber, string, boolean мы просто создаём ещё один object, который получает новое свйоство, а потом записывается в никуда. Правило конвертации простое:

  • если присвоили object — оставляем как есть
  • если присвоили unde­fined, кидаем excep­tion
  • во всех прочих случаях — new Number(input), new String(input) или new Boolean(input)

JavaScript: быстрый floor и приведение объектов

Чудесное от Михаила Барановского:

В JavaScript можно писать через степень:

var a = 120000; // make it shorter?
var a = 12e4;

 

var a = Math.floor(b);
// если b всегда > 0, можно сократить до:
var a = ~~b;

Легко получать текущую дату:

var date = +new Date;

Это работает, потому что + дёргает val­ue­of.

var a = new Boolean(false); // how to quickly check if (a)?
alert(typeof a); // "object"
alert(!!a); // always true, because a is an object
alert(!!+a);
// right result, because "+" is calling valueOf
// method and convert result to number "0..1"
alert(a>0); // even shorter