Используя coldfusion, как мне отобразить элементы массива в случайном порядке? - PullRequest
1 голос
/ 03 ноября 2011

Используя ColdFusion, моя цель - выводить все элементы массива в абсолютно случайном порядке. В моем массиве 6000 элементов, извлеченных из файла XML.

Обычно, если бы я не требовал, чтобы они выводились в случайном порядке, я сделал бы это:

<cfoutput>
<cfloop from="1" to="#arraylen(thestring)#" index="x">
#thestring[x]#<br/>
</cfloop>
</cfoutput>

В результате мои строки отображаются в том порядке, в котором они были извлечены из файла XML:

thestring[1]
thestring[2]
thestring[3]
thestring[4]

Etc. и т.д. вплоть до строки [6000].

Я хотел бы видеть все элементы, выводимые в совершенно случайном порядке:

thestring[5]
thestring[22]
thestring[4301]
thestring[201]
thestring[2041]

Ответы [ 5 ]

2 голосов
/ 04 ноября 2011

Я использовал такие вещи много раз с большим успехом.Я никогда не пробовал это на 6000 предметов, хотя.Это один из способов убрать кошку.

<!--- create list of unusused indexes --->
<cfset ListOfUnusedIndexes = "">
<cfset ItemsRemaining = "#arrayLen(YourArray)#">

<!--- populate list from 1 to lenght of array --->
<cfloop from="1" to="#arrayLen(YourArray)#" index="i">
   <cfset ListOfUnusedIndexes = listAppend(ListOfUnusedIndexes , i)>
</cfloop>

<!--- loop through ---->
<cfloop from="1" to="#arrayLen(YourArray)#">
  <!--- pick a random index from 1 to the number of items remaining --->
  <cfset RandomNumber = randRange(1, ItemsRemaining)>
  <!--- get that index from the list of unused numbers --->
  <cfset IndexToGet = listGetAt(ListOfUnusedIndexes, RandomNumber)>
  <!--- output the item from your array --->
  <cfset ArrayItemToOutput = thestring[IndexToGet]>
  <!--- remove the index from your list of unusued indexes --->
  <cfset ListOfUnusedIndexes = listDeleteAt(ListOfUnusedIndexes, IndexToGet)>
  <!--- decrement the number of items remaining --->
  <cfset ItemsRemaining = ItemsRemaining - 1>
</cfloop>
1 голос
/ 04 ноября 2011

Потенциальная проблема с отслеживанием «используемых» элементов состоит в том, что может быть намного больше итераций, чем необходимо для вывода всех элементов. Например, предположим, что элемент 10 был первым отображаемым элементом, отслеживая его по мере использования, возможно, что 10 снова появится в randrange (), прежде чем все элементы будут отображены. Чем больше элементов «используется», тем выше вероятность того, что нам потребуется добавить итерацию, чтобы получить элемент, который не использовался.

Один из способов убедиться, что мы делаем только 6000 итераций, - это уменьшить размер массива при каждой итерации и выполнить randRange (1, arrayLen ({имя массива})).

//set up array
test = [];
for( x=1; x<=6000; x++ ){
    arrayAppend( test, "Item " & x );

}

//here is the meat of the process
done = false;
count = 1;
while( !done ){
    index = randRange( 1, arrayLen( test ) );
    writeOutput( count & " : " & test[ index ] & "<br/>" );
    arrayDeleteAt( test, index );
    count++;
    done = !arrayLen( test );
}

Приведенный выше код в среднем выполнялся на моей машине разработки менее 100 мс.

Кроме того, после тестирования кода Генри я заметил, что его можно немного подправить, вот слегка оптимизированный код.

<!--- set up the array --->
<cfset theString = []>
<cfloop from="1" to="6000" index="i">
    <cfset arrayAppend(theString, "Item : " & i) />
</cfloop>

<cfset collections = createObject("java","java.util.Collections") />
<cfset collections.shuffle( theString ) />
<cfoutput>

<cfloop array="#theString#" index="x">
    #x#<br/>
</cfloop>
</cfoutput>

Обратите внимание, что я избавился от arrayresize (), и вы можете просто передать исходный массив в collection.shuffle () и затем выполнить цикл по нему.

1 голос
/ 04 ноября 2011

на основе неповторяющихся случайных чисел , Алгоритм тасования Фишера-Йейтса - это то, что вам нужно, и оно уже реализовано в java.util.Collections shuffle(), см .: Что делает Java Collections.shuffle?

<cfset indices = []>
<cfset arrayResize(indices, 6000)>
<cfloop from="1" to="6000" index="i">
    <cfset arrayAppend(indices, i)>
</cfloop>

<cfset collections = createObject("java","java.util.Collections")>
<cfset collections.shuffle(indices)>

<cfloop array="#indices#" index="x">
    #thestring[x]#<br/>
</cfloop>

Очень эффективно. Для 6000 предметов требуется всего ~ 3 мс, используя быстрый тест getTickCount() на моем ПК.

1 голос
/ 04 ноября 2011

Обновление: Это было скорее быстрое демо, чтобы продемонстрировать, что более раннее предложение будет работать.Но некоторые другие предложения более упорядочены.Поэтому я бы рекомендовал вместо этого использовать один из них.

На основании вашего последнего обновления я не вижу причин, по которым предложение Рэймонда не сработало бы.Пока вы отслеживаете элементы уже отображаются.Вот простой пример

<cfscript>
    // generate sample array
    yourArray = [];
    for (x = 1; x <= 20; x++) {
            arrayAppend(yourArray, "item "& x);
    }

    // stores used indices
    visited = {};
    for (x = 1; x <= arrayLen(yourArray); x++) {

            // get a random index we have not seen before
            do {
                    index = randRange(1, arrayLen(yourArray));
            }
            while (structKeyExists(visited, index));

            // display it
            WriteOutput(yourArray[index] &"<br>");

            // mark are "visited" so we do not display it again
            visited[index] = true;
    }
</cfscript>
0 голосов
/ 03 ноября 2011

Цикл от 1 до N, где N - это количество раз, которое вы хотите зациклить, а затем просто выбрать случайный элемент, используя randRange (1, arraylen (thestring)).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...