Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Задачка по генерации чисел (https://javascript.ru/forum/misc/60372-zadachka-po-generacii-chisel.html)

Untropee 25.12.2015 03:26

Задачка по генерации чисел
 
Приветствую! Помогите решить задачку на генерацию чисел.

Примерно понимаю, нужно в цикле пустить Math.random

Нужно сгенерировать набор из 20ти цифр (без пробелов), пример (для наглядности с пробелами):

2 10 19 15 8 0 3 5 11 17 2 1 2 0 1 0 2 1 0 2

Структура: первые 10 цифр от 0 до 19 (повторяться запрещено), следующие 10 цифр от 0 до 2

ruslan_mart 25.12.2015 04:01

var data = new Array(20),
	i = 0, n;

function getRandomInt(n) {
	return Math.floor(Math.random() * ++n);
}

while(i < 10) {
	n = getRandomInt(19);
	if(data.indexOf(n) < 0) {
		data[i] = n;
		data[i + 10] = getRandomInt(2);
		i++;
	}
}

alert( data );
alert( data.join('') );

Deff 25.12.2015 04:05

function indexRandom(lng){
     var a = {},i,out=[],n=0; 
     while (n!=lng){
       i = Math.floor(lng*Math.random());
       if(typeof(a[i])=='undefined'){
         a[i]=i; out.push(i);
         n++;
       }
     }
    return out;
  }
 
  var arr = [],ind = indexRandom(20),k;
  for(i=0;i<20;i++) arr[i]=ind[i]%(k=i<10?20:3);

  alert(arr)
  alert(arr.join(''))

ruslan_mart 25.12.2015 04:07

Deff, 3 цикла? :blink:

Untropee 25.12.2015 04:12

Спасибо, сейчас попробую) Я тоже начал, уже практически закончил, но косячнул видимо на проверке повторяющихся числе в первой десятке (повторяющиеся числа остаются).

//Функция генерации
function randomInteger(min, max) {
    var rand = min - 0.5 + Math.random() * (max - min + 1)
    rand = Math.round(rand);
    return rand;
}
//Создаём массив
var numb = [];

//Начинаем заполнять массив

for (i=0;i<=19;i++) {
	
	//Пошла первая десятка
	
	if (i < 10) {
		
		var my_numb = randomInteger(0, 19);
		numb[i] = my_numb;
		
		if (i > 0) {
			
			//Функция проверки повторов
		
			check_numb()
			function check_numb() {
		
				for (l=0;l<=i-1;l++) {
					
					if (numb[l] == my_numb) {
						
						alert(my_numb)
						numb[l] = randomInteger(0, 19);
						check_numb()
						
					}
					
				}
			
			}
		
		}
		
	}
	
	//Пошла вторая десятка
	
	if (i > 9) {
		
		numb[i] = randomInteger(0, 2)
		
	}
	
}

alert(numb.join(''));

Untropee 25.12.2015 04:16

Спасибо, всё работает у вас.

Я побыдлокодил конечно, но действовал исходя из логики и недостатка знаний)

рони 25.12.2015 09:46

:) random только 20 раз и никаких повторов :dance:
<script>
Array.prototype.shuffle = function() {
    for (var a = this.length; 0 <= a; a--) {
        var b = Math.floor(Math.random() * (10 > a ? 3 : a + 1)),
            c = 10 > a || void 0 === this[b] ? b : this[b];
        10 < a && (this[b] = void 0 === this[a] ? a : this[a]);
        this[a] = c
    }
    return this.reverse()
};
var arr = new Array(20).shuffle();
document.write(arr+"<br>"+arr.join(''))
</script>

Deff 25.12.2015 17:31

рони, ++
Да, скоростью я был удивлён еще в табличке
================
Вариант рандомного массива без повторений с вызовом Math.random() единожды на каждый элемент:
function indRand(lng){
     var a = [],i,out=[],n=lng;
     for(i=0;i<lng;i++)a[i]=i;
     while (n--)out.push(a.splice(Math.floor((n+1)*Math.random()),1)[0]);
     return out;
  }

 var arr = [],ind = indRand(20),k;
 for(i=0;i<20;i++) arr[i]=ind[i]%(k=i<10?20:3);

 alert(arr)
 alert(arr.join(''))

рони 26.12.2015 13:20

Deff,
на всякий случай, надобы поправить indRand, когда-то я сам прокололся на таком использовании splice :cray:

Deff 26.12.2015 13:51

рони,
Если массив создаешь внутри функции, вроде как фичи нет,...
А вообще интересно, как оно обходит созданные прототипы и выходит на начальный родитель(ксать можно использовать(Это если массив передаём в функцию)

Или ты не об этом ? Тады ап чём ?

EmperioAf 26.12.2015 14:33

Ув. рони,
Ув. Deff,
объясните пожалуйста чем плох код, предложенный Ruslan_xDD в этом посте?
То, что он предложил легко читается и очевидное решение. А ваши решения выглядят со стороны как навороты. Только без обид. Просто любопытно

Deff 26.12.2015 14:59

Цитата:

Сообщение от EmperioAf
Просто любопытно

1. Есть некая соревновательсть в решениях, типично в топиках коротких скриптов и кодов, и достаточно нередко используемых
Автор уже доволен, но применяемый код мон вылизать.
Где-то был даж спец. топик с такими скриптами-задачками
==================================
К примеру у нас с Рони как то была задача протестить код на миллионе повторов. При неотлизанном коде - это часы...
К примеру тот жа Math.random() на массиве в 10 элементов вызывается средне=статистически при таких функциях неповторяющейся выборки 29 раз - на 20 - 70 при дальнейшем увеличении массива растёт в какой-то степени(посколь попадает в уже выбранные значения)
Т.е. время на коротких массивах растёт вдвое-втрое

рони 26.12.2015 15:12

Цитата:

Сообщение от Deff
Или ты не об этом ?

посмотри что выдаёт функция indRand :)

Deff 26.12.2015 15:19

Цитата:

Сообщение от рони
посмотри что выдаёт функция indRand

Тещу в Опере и Мозилле - всё в норме... (Сделай красивый скриншот плиз.. мож я не выспался...
======================

рони 26.12.2015 15:20

EmperioAf,
код Ruslan_xDD генерирует числа Math.random более 20 раз чтоб избежать повторов, мой код генерирует только 20 раз и без повторов.

рони 26.12.2015 15:20

Deff,
в консоли посмотри :)

Deff 26.12.2015 15:57

рони,
Ок :(
================
// Тест средне-статистического числа повторов Math.random() на создание неповторяющегося массива из 1000 элементов
function indexRandom(lng){
    var numRnd = 0;
     var a = {},i,out=[],n=0; 
     while (n!=lng){
       i = Math.floor(lng*Math.random()); numRnd++;
       if(typeof(a[i])=='undefined'){
         a[i]=i; out.push(i);
         n++;
       }
     }
    return numRnd;
  }
function repeat(n){
  var N=0;n2=n
  while (--n2){
     N+= indexRandom(1000);
  }
  return N/n;
}
alert('N='+repeat(10000))


// Тест средне-статистического числа повторов Math.random() на создание неповторяющегося массива из 20 элементов
function indexRandom(lng){
    var numRnd = 0;
     var a = {},i,out=[],n=0; 
     while (n!=lng){
       i = Math.floor(lng*Math.random()); numRnd++;
       if(typeof(a[i])=='undefined'){
         a[i]=i; out.push(i);
         n++;
       }
     }
    return numRnd;
  }
function repeat(n){
  var N=0;n2=n
  while (--n2){
     N+= indexRandom(20);
  }
  return N/n;
}
alert('N='+repeat(10000))


// Тест средне-статистического числа повторов Math.random() на создание неповторяющегося массива из 10 элементов
function indexRandom(lng){
    var numRnd = 0;
     var a = {},i,out=[],n=0; 
     while (n!=lng){
       i = Math.floor(lng*Math.random()); numRnd++;
       if(typeof(a[i])=='undefined'){
         a[i]=i; out.push(i);
         n++;
       }
     }
    return numRnd;
  }
function repeat(n){
  var N=0;n2=n
  while (--n2){
     N+= indexRandom(10);
  }
  return N/n;
}
alert('N='+repeat(10000))

=======================
Зы: Примерная апроксимация кол-ва обращений к Math.random() по четырём точкам:
n - длина массива
x = n+n^1.26

рони 26.12.2015 16:01

Цитата:

Сообщение от Deff
while (n--) out.push(a.splice(Math.floor((n+1)*Math.random()), 1)[0]);

:-?

Deff 26.12.2015 16:21

рони,
СПС, - я понял, тут отвлекают(отхожу от компа + возгорелся протестить: А скок реально рандомов лишних ? ) поэтому долго с правкой того поста

Deff 26.12.2015 16:31

рони,
А эту феньку видел ?
function abc(arr){
  var a = arr.splice(0,3);
}

var arr = [1,2,3];
abc(arr);
alert('>'+arr+'<')


function abc(arr){
  function abcd(ar2){
     var a = ar2.splice(0,3);
  }
  abcd(arr)
}

var arr = [1,2,3];
abc(arr);
alert('>'+arr+'<')


function abc(arr){
  arr=[];
}

var arr = [1,2,3];
abc(arr);
alert('>'+arr+'<')

рони 26.12.2015 17:42

Создание массива с уникальными данными и в указанном диапазоне
 
функция заполняет массив уникальными данными в указанном диапазоне или перемешивает исходный, если диапазон не указан заполняет от нуля по порядку.
в трёх примерах ниже генерация происходит только пять раз.(исходная длина массива)

<script>
Array.prototype.randomShuffle = function(min,max) {
  min = min || 0;
  max = ++max || this.length;
  var len = max - min;
  max = len - this.length;
  this.length = len;
    for (var a = this.length-1; 0 <= a; a--) {
       if(a < max) {break}
        var b = Math.floor(Math.random() * a),
            c = void 0 === this[b] ? (b + min) : this[b];
            this[b] = void 0 === this[a] ? (a + min) : this[a];
            this[a] = c
    }
    this.reverse();
    this.length -= max;
    return this
};
var arr = Array(5).randomShuffle();
document.write(arr+"<br>")
var arr = Array(5).randomShuffle(-100,100);
document.write(arr+"<br>")
var arr =[1,2,3,4,5].randomShuffle();
document.write(arr+"<br>")
document.write(["Собака след не взяла, Взяла", "но была убита убегающим", "след потеряла"].randomShuffle()+"<br>")
</script>

рони 26.12.2015 18:14

Deff,
не осилил

рони 26.12.2015 18:30

Deff,
ок, ничего не мешает вынести предложенный метод из прототипа в отдельную функцию, но меня твои аргументы не убедили,
по моему проще если нужно сделать arr.slice().shuffle() чем slice добавлять в функцию.

Deff 26.12.2015 18:30

function indRand(a){
     var out=[],n=a.length; a=a.slice(0);
     while (n--){out.push(a.splice(Math.floor((n+1)*Math.random()),1)[0]);}
     return out;
  }
var tim = +new Date
var arr='1234567890'.split('');

n=1000000;
while (n--){
  var b = indRand(arr);
}

alert((+new Date-tim)/1000);


Array.prototype.shuffle = function(min,max) {
  min = min || 0;
  max = ++max || this.length;
  var len = max - min;
  max = len - this.length;
  this.length = len;
    for (var a = this.length-1; 0 <= a; a--) {
       if(a < max) {break}
        var b = Math.floor(Math.random() * a),
            c = void 0 === this[b] ? (b + min) : this[b];
            this[b] = void 0 === this[a] ? (a + min) : this[a];
            this[a] = c
    }
    this.reverse();
    this.length -= max;
    return this
};

var tim = +new Date
var arr='1234567890'.split('');

n=1000000;
while (n--){
  var arr =arr.shuffle();
}

alert((+new Date-tim)/1000);

Твой Вариант значительно быстрее!
Гы, а на длинных массивах, длиной более 100, преимущество в 8 и более раз! :dance:

Deff 26.12.2015 19:22

Ксать подобная перестановка в математике обзывается
randomShuffle (Имхо более говорящее название, нативный перевод как: случайная перестановка из массива существующих)
==============================
Выложил бы на Хабре - Фишка весьма востребованная ( к примеру для массовой генерации паролей или ключей (Видел сотни вопросов про как сделать - всё примерно делали как в посте от Ruslan_xDD...
Упор делать на "быстрая!"
.

рони 26.12.2015 19:34

Deff,
randomShuffle ок :)
Array.prototype.randomShuffle = function(c, b) {
    c = c || 0;
    b = ++b || this.length;
    var a = b - c;
    b = a - this.length;
    this.length = a;
    for (a = this.length - 1; 0 <= a && !(a < b); a--) {
        var d = Math.floor(Math.random() * a),
            e = void 0 === this[d] ? d + c : this[d];
        this[d] = void 0 === this[a] ? a + c : this[a];
        this[a] = e
    }
    this.reverse();
    this.length -= b;
    return this
};
alert(Array(5).randomShuffle())

Deff 26.12.2015 23:43

Посмотри такой нюанс при max<2
var arr = Array(5).shuffle(-1,1);
Либо нун пояснить про диапазон c, b

рони 27.12.2015 11:16

Deff,
защиты от дурака я не встраивал :)

рони 27.12.2015 12:07

:write:
чуть сократил ещё :)
Array.prototype.randomShuffle = function(c, b) {
    c = c || 0;
    b = ++b || this.length;
    var a = b - c;
    b = a - this.length;
    this.length = a--;
    for (; 0 <= a && !(a < b); a--) {
        var d = Math.floor(Math.random() * a),
            e = void 0 === this[d] ? d + c : this[d];
        this[d] = void 0 === this[a] ? a + c : this[a];
        this[a] = e
    }
    this.reverse();
    this.length -= b;
    return this
};
alert( Array(5).randomShuffle(-1,1))//заполнение пустого массива идёт на длину указанного диапазона от min до max
alert( Array(5).randomShuffle(-10,10))

Deff 27.12.2015 13:24

рони, Т.е, если массив длинной 5, разность мин-мах диапазона проставленного в параметрах [a,b] вызова метода randomShuffle(a,b) должна быть не меньше пяти, для полного заполнения массива уникальными значениями ( Я задаю типовые вопросы, согласно любому представления нового скрипта на Хабре, вот я ап чём) Для тренировки :yes:

рони 27.12.2015 13:26

Deff,
да :) и min < max

Deff 27.12.2015 13:42

:) Нашел готовую решабелку по судоку, единственное оформить поудобнее-посимпатичней


Часовой пояс GMT +3, время: 15:56.