Как я могу сделать случайные не выводить повторяющиеся ответы на строки в пакете? [Дубликат]

Во-первых, вам нужно иметь четкое представление о scope и поведении ключевого слова this в контексте scope.

this & amp; scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this ключевое слово в глобальной области относится к объекту window. Внутренняя функция this также относится к объекту window.So this всегда будет ссылаться на окно до тех пор, пока мы найдем способ манипулировать this, чтобы указать контекст по собственному выбору.

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

Различные способы управления this внутри функций обратного вызова:

Здесь У меня есть функция-конструктор, называемая Person. Он имеет свойство, называемое name, и четыре метода, называемые sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Все четыре из них имеют одну конкретную задачу. Заберите обратный вызов и вызовите его. Обратный вызов имеет конкретную задачу, которая заключается в регистрации свойства имени экземпляра функции конструктора Person.

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX (X относится к 1,2,3,4) методу с niceCallback, чтобы увидеть, как много способов управления this внутри обратного вызова ссылаться на person.

var p1 = new Person('zami') // create an instance of Person constructor

bind:

Что нужно сделать, это создать новую функцию с ключевым словом this, установленным на предоставленное значение.

sayNameVersion1 и sayNameVersion2 используют bind для управления this функции обратного вызова.

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

сначала связывают this с обратным вызовом внутри самого метода. для второго обратного вызова передается связанный с ним объект.

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

вызов:

first argument в call используется как функция this внутри функции, которая вызывается с call, прикрепленной к ней.

sayNameVersion3 использует call для управления this ], чтобы ссылаться на созданный нами объект person, а не на объект окна.

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

и он называется следующим:

p1.sayNameVersion3(niceCallback)

apply:

Как и в call, первый аргумент apply относится к объекту, который будет обозначен ключевым словом this.

sayNameVersion4 использует apply для манипулирования this для обращения к объекту человека

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

, и он называется следующим. Просто передается обратный вызов,

p1.sayNameVersion4(niceCallback)

3
задан aschipfl 22 December 2015 в 01:24
поделиться

4 ответа

Я немного изменил код, который я написал некоторое время назад:

@echo off
setlocal EnableDelayedExpansion

rem total number of random numbers:
set /A "RND_TOTAL=8"
rem range for random numbers (minimum, maximum):
set /A "RND_MIN=1, RND_MAX=10"

set /A "range=RND_MAX-RND_MIN+1"

rem Create an input list with all numbers in given range
set "input="
for /L %%i in (%RND_MIN%,1,%RND_MAX%) do (
   set "input=!input! %%i"
)
set "input=%input% "
echo  IN: [%input%]

rem Extract RND_TOTAL elements from input list in random order
set "output="
for /L %%i in (%RND_TOTAL%,-1,1) do (
   set /A "randIndex=(!random!*range)/32768+1, range-=1"
   call :MoveInputToOutput !randIndex!
)
echo OUT: [%output%]

goto :EOF

:MoveInputToOutput randIndex
for /F "tokens=%1" %%n in ("%input%") do (
   set output=%output% %%n
   set input=!input: %%n = !
)
exit /B

Пример вывода:

> test
 IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 8 7 9 3 1 4 5 2]

> test
 IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 9 2 10 6 4 8 5 1]

> test
 IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 1 2 4 3 8 5 7 9]

Извините, но я не понимаю, что %RND_INTER% значение используется для ...

EDIT: новая версия, которая использует значение %RND_INTER% и не имеет ограничения на количество генерируемых случайных чисел.

@echo off
setlocal EnableDelayedExpansion

rem total number of random numbers:
set /A "RND_TOTAL=8"
rem range for random numbers (minimum, maximum, interval):
set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1"

rem Create an input vector with all numbers in given range
set "n=0"
for /L %%i in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do (
   set /A n+=1
   set "in[!n!]=%%i"
)
echo Input:
set in[
echo/

rem Extract RND_TOTAL elements from input vector in random order
for /L %%i in (1,1,%RND_TOTAL%) do (
   set /A "randIndex=(!random!*n)/32768+1"
   set /A "out[%%i]=in[!randIndex!], in[!randIndex!]=in[!n!], n-=1"
)
echo Output:
set out[
4
ответ дан Aacini 21 August 2018 в 17:54
поделиться
  • 1
    Спасибо за этот классный подход, @Aacini! RND_INTER определяет интервал, т. е. размер шага в данном диапазоне; например, RND_MIN=0, RND_MAX=15, RND_INTER=3, тогда случайная последовательность может содержать 0 3 6 9 12 15 ... – aschipfl 22 December 2015 в 10:04
  • 2
    К сожалению, это поддерживает максимум 31 возможное значение из-за того, что FOR / F не может читать более 31 токенов. См. мой ответ для варианта, который использует записи с постоянной шириной в сочетании с подстрочными операциями, поддерживая тем самым многие другие значения. – dbenham 22 December 2015 в 17:58
  • 3
    @aschipfl: см. новую версию, использующую значение RND_INTER – Aacini 22 December 2015 в 19:56
  • 4
    @dbenham: Ну, простая модификация позволяет хранить элементы в массиве, которые не ограничивают число элементов. На самом деле новый метод проще первого, потому что все перемещения данных могут выполняться непосредственно в парах SET /A командах ... – Aacini 22 December 2015 в 20:01
  • 5
    Ницца. Мой мозг не помог мне какое-то время - для меня не было очевидным, как вы удаляете выбранное значение из массива. Хороший момент для вашего метода заключается в том, что он не ограничивает количество возможных значений (кроме ограничений CMD). Однако мой строковый метод на 40% быстрее (пока вы не превысите его ограничения). Min = 1, Max = 1000, Inter = 1, Total = 100: ваш массив = 360 мс, мой str = 220 мс. – dbenham 22 December 2015 в 20:41

Несмотря на то, что вы, ребята, выложили действительно отличные решения, у меня нет сердца, чтобы просто сдаться, и поэтому мне пришлось попробовать его самостоятельно, чтобы найти лучший код, который я разместил в вопросе; здесь мы идем ...

Основная идея состоит в том, чтобы создать таблицу, состоящую из двух столбцов, где первая содержит случайные числа с дубликатами, а вторая содержит индексы, которые составляют все возможные случайные числа. Следующим шагом будет сортировка этой таблицы по первому столбцу. Наконец, вам нужно выбрать значения из второго столбца из числа строк, в которых вам нужны случайные числа (в моем подходе я использую последние строки). Все полученные номера уникальны, так как второй столбец не содержит дубликатов. Вот пример, если нам нужны 8 случайные числа из 1,2,3,4,5,6,7,8,9,10:

generated   sorted      returned
table       table       numbers
--------------------------------
1,1         1,1         -
9,2         1,6         -
8,3         10,8        8
3,4         3,4         4
9,5         4,7         7
1,6         5,9         9
4,7         8,10        10
10,8        8,3         3
5,9         9,2         2
8,10        9,5         5

Как вы можете видеть, нет дублирующихся чисел. Большим преимуществом этого метода является то, что вычисление случайных чисел не нужно повторять, если тот же уже был использован. Недостатком является то, что полная таблица должна быть создана даже в том случае, если из огромного пула возможных чисел требуется только несколько уникальных случайных чисел.

Я должен признать, что этот метод не является моей идеей, но, к сожалению, я не знаю, кому это зачисляется ...


Вот мой код, содержащий некоторые пояснительные замечания:

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem total number of random numbers, duplicate flag (`0` means no duplicates):
set /A "RND_TOTAL=8, FLAG_DUP=0"
rem range for random numbers (minimum, maximum, interval):
set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1"
rem write table-like data to temporary file:
> "%~n0.tmp" (
    rem loop through all possible random numbers:
    for /L %%I in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do (
        rem compute a random number:
        set /A "RND_NUM=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
        if %FLAG_DUP% EQU 0 (
            rem duplicates denied, so build row with random number as first column:
            echo !RND_NUM!,%%I
        ) else (
            rem duplicates allowed, so build row with loop counter as first column:
            echo %%I,!RND_NUM!
        )
    )
)
rem determine how many items of the table need to be skipped to get total number:
set /A "SKIP=(RND_MAX-RND_MIN)/RND_INTER+1, SKIP-=RND_TOTAL"
if %SKIP% GTR 0 (
    set "SKIP=skip=%SKIP% "
) else (
    set "SKIP="
)
rem read table-like data from temporary file:
set /A "RND_COUNT=0"
< "%~n0.tmp" (
    rem sort rows (lines) of table-like data alphabetically, enumerate them:
    for /F "%SKIP%tokens=2 delims=," %%N in ('sort') do (
        set /A "RND_COUNT+=1"
        rem store and return random number:
        set /A "RND_NUM[!RND_COUNT!]=%%N"
        echo %%N
    )
)
rem clean up temporary file:
del /Q "%~n0.tmp"
endlocal
exit /B

В этом скрипте вышеописанные табличные данные хранятся во временном файле, который затем передается команде sort, которая выполняет сортировку по алфавиту.

Полученная случайная последовательность выводится на консоль и сохраняется в array-like variables RND_NUM[1:8] (который доступен только до тех пор, пока команда endlocal не будет выполнена).


Обновление:

Исходя из того, что set также может сортироваться и что описанная выше таблица также может быть отражена в именах переменных окружения в стиле, подобном двумерному массиву (здесь я использовал RND_NUM[_,_]), следующий скрипт больше не использует временную файл. случайная последовательность снова выводится на консоль и также сохраняется в 1D-массиве RND_NUM[1:8]).

Но прежде чем мы перейдем к скрипту, я хочу показать вам 2D-массив, который представляет упомянутый таблицу с теми же данными образца, что и выше (обратите внимание, что значения переменных совершенно неактуальны):

generated           sorted              returned
2D-array            2D-array            numbers
------------------------------------------------
RND_NUM[1,1]        RND_NUM[1,1]        -
RND_NUM[9,2]        RND_NUM[1,6]        -
RND_NUM[8,3]        RND_NUM[10,8]       8
RND_NUM[3,4]        RND_NUM[3,4]        4
RND_NUM[9,5]        RND_NUM[4,7]        7
RND_NUM[1,6]        RND_NUM[5,9]        9
RND_NUM[4,7]        RND_NUM[8,10]       10
RND_NUM[10,8]       RND_NUM[8,3]        3
RND_NUM[5,9]        RND_NUM[9,2]        2
RND_NUM[8,10]       RND_NUM[9,5]        5

Вот код (включая некоторые пояснительные замечания):

@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem total number of random numbers, duplicate flag (`0` means no duplicates):
set /A "RND_TOTAL=8, FLAG_DUP=0"
rem range for random numbers (minimum, maximum, interval):
set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1"
rem clean up all variables named `RND_NUM*` (optionally):
call :CLEANUP1
rem loop through all possible random numbers:
for /L %%I in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do (
    rem compute a random number:
    set /A "RND_INDEX=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
    if %FLAG_DUP% EQU 0 (
        rem duplicates denied, so build 2D-array with random number as first index:
        set "RND_NUM[!RND_INDEX!,%%I]=#"
    ) else (
        rem duplicates allowed, so build 2D-array with loop counter as first index:
        set "RND_NUM[%%I,!RND_INDEX!]=#"
    )
)
rem determine how many items of the 2D-array need to be skipped to get total number:
set /A "SKIP=(RND_MAX-RND_MIN)/RND_INTER+1-RND_TOTAL"
if %SKIP% GTR 0 (
    set "SKIP=skip=%SKIP% "
) else (
    set "SKIP="
)
rem let `set` output all `RND_NUM*` variables sorted alphabetically, enumerate them:
set /A "RND_COUNT=0"
for /F "%SKIP%tokens=3 delims=[,]" %%I in ('set "RND_NUM"') do (
    set /A "RND_COUNT+=1"
    rem store and return random number:
    set "RND_NUM[!RND_COUNT!]=%%I"
    echo %%I
)
rem clean up all 2D-array variables named `RND_NUM*,*` (optionally):
call :CLEANUP2
endlocal
exit /B

:CLEANUP1
for /F "tokens=1 delims==" %%I in ('2^> nul set "RND_NUM"') do (
    set "%%I="
)
exit /B

:CLEANUP2
for /F "tokens=1,2,3 delims=,=" %%I in ('set "RND_NUM"') do (
    if not "%%K"=="" (
        set "%%I,%%J="
    )
)
exit /B

Процедуры очистки :CLEANUP1 и :CLEANUP2 считаются необязательными и просто удаляют любые переменные, имена которых начинаются с RND_NUM (см. :CLEANUP1) в начале и имена которых содержат , (что верно для 2D-массива, но не для 1D-массива, см. :CLEANUP2) в конце.

0
ответ дан aschipfl 21 August 2018 в 17:54
поделиться

Исходное решение Aacini эффективно, однако оно может поддерживать максимум 31 возможное значение, потому что FOR / F не может читать более 31 токенов. EDIT - его второе решение устранило ограничение.

Ниже приведено аналогичное понятие, которое использует постоянную ширину для чисел в списке. Это позволяет мне легко использовать операции подстроки для извлечения случайно выбранных значений и для удаления каждого значения из списка.

Как написано, это решение поддерживает значения от 0 до 9999 с максимальным количеством возможных значения & lt; = 1354.

Я использовал очень похожую стратегию для управления случайным размещением продуктов в моей игре SNAKE.BAT . Мне нужно было отслеживать все пустые места в игровом поле и случайным образом выбирать новое расположение продуктов из этого списка.

@echo off
setlocal enableDelayedExpansion

:: This script has the following limitations:
::   RND_MIN >= 0
::   RND_MAX <= 9999
::   ((RND_MAX - RND_MIN + 1) / RND_INTER) <= 1354
::
set "RND_MIN=1"
set "RND_MAX=10"
set "RND_INTER=1"
set "RND_TOTAL=8"

set /a cnt=(RND_MAX - RND_MIN + 1) / RND_INTER

:: Define a string containing a space delimited list of all possible values,
:: with each value having 10000 added
set "pool="
set /a "beg=RND_MIN+10000, end=RND_MAX+10000, cnt=(RND_MAX-RND_MIN+1)/RND_INTER"
for /l %%N in (%beg% %RND_INTER% %end%) do set "pool=!pool!%%N "

:: Build the randomly sequenced array of numbers
for /l %%N in (1 1 %RND_TOTAL%) do (

  %= Randomly select a value from the pool of all possible values  =%
  %= and compute the index within the string, as well as the index =%
  %= of the next value                                             =%
  set /a "loc=(!random!%%cnt)*6, next=loc+6"

  %= Transfer the index values to FOR variables =%
  for %%A in (!loc!) do for %%B in (!next!) do (

    %= Assign the selected value to the output array =%
    set /a "RND_NUM[%%N]=!pool:~%%A,5!-10000"

    %= Remove the value from the pool =%
    set "pool=!pool:~0,%%A!!pool:~%%B!"
    set /a cnt-=1

  )
)

:: Display the results
for /l %%N in (1 1 %RND_TOTAL%) do echo !RND_NUM[%%N]!
2
ответ дан dbenham 21 August 2018 в 17:54
поделиться

замените

for /L %%I in (1,1,%RND_TOTAL%) do (
    rem compute a random number:
    set /A "RND_NUM[%%I]=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
    echo !RND_NUM[%%I]!
)

на

for /L %%I in (%rnd_min%,1,%RND_max%) do set "rnd_num{%%I}="
set /a rnd_count=rnd_total
:rnd_loop
rem compute a random number:
set /A "RND_selection=%RANDOM%%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
if not defined rnd_num{%rnd_selection%} (
 SET "rnd_num{%rnd_selection%}=Y"
 set /a rnd_num[%count%]=rnd_selection
 echo %rnd_selection%
 set /a rnd_count-=1
)
if %rnd_count% neq 0 goto rnd_loop

Каждый раз, когда выбор сделан, rnd_num{selectionmade} установлен на Y, поэтому, если он выбран снова, это и запись / выход / счет-1-меньше пропускается.

1
ответ дан Magoo 21 August 2018 в 17:54
поделиться
  • 1
    Это лучше, чем оригинал OP. Но он все равно может стать очень медленным, если есть тысячи возможных значений, и осталось только несколько невостребованных значений. – dbenham 22 December 2015 в 17:56
Другие вопросы по тегам:

Похожие вопросы: