cfloop над массивом/списком не разрешает ссылаться на предыдущие значения

Я часто использую cfloop для массива или списка, потому что мне приходится выполнять сложные вычисления со значениями массива. Однако, похоже, нет способа вернуться к конкретному члену массива/списка. Если я использую обычный цикл, я могу легко это сделать:

<cfloop from = "1" to = "#ArrayLen(myarray)#" index = "i">
<cfset temp = "myarray[i]">
<cfif mystruct[temp] GT 5>
  ... do something
</cfif>
<cfif myarray[i] NEQ myarray[i-1]>
  ...do something
</cfif>
</cfloop>

но вычисления, связанные с myarray[i], могут быть громоздкими, когда я должен ссылаться на них по «i», а не по значению в i.

Но если я использую цикл над массивом, мне часто приходится добавлять счетчик:

<cfset m = 0>
<cfloop array = #myarray# index = "value">
<cfset m = m + 1>
<cfif mystruct[value] GT 5>
 ... do something
</cfif> 
<cfif myarray[i] NEQ myarray[i-1]>
  ...do something
</cfif>
</cfloop>

Кто-нибудь знает, как ссылаться на myarray[i-1] в кодировке cfloop array = myarray? Исследуя это, я нашел это разглагольствование: http://www.markdrew.co.uk/blog/post.cfm/cfloop-rant , но решений не предлагает.


person Betty Mock    schedule 13.06.2013    source источник
comment
используйте свой собственный счетчик, как во втором примере, но измените m на i. Имейте в виду, что i-1 может дать 0 (индекс CF основан на 1, 0 выходит за пределы), поэтому проверьте пограничный случай.   -  person Henry    schedule 13.06.2013
comment
Обычно я просто использую ваше первое решение, когда мне приходится прыгать по отношению к текущему индексу, как вы предлагаете, и использовать cfloop array = "" для основных циклов. есть ли причина, по которой вы пытаетесь избежать индексного цикла?   -  person Travis    schedule 13.06.2013
comment
извините за м - я отключаюсь   -  person Betty Mock    schedule 14.06.2013
comment
Потребуется счетчик, если myArray является 2D или более и зацикливается на массиве, а не на счетчике для ссылки на элементы <cfset cnt=1><cfloop index="idxTempArray" array="#my2DArray">#idxTempArray[2]#...<cfif cnt++ gt 5>...do after something 5th element...</cfif></cfloop>. (Обратите внимание, что cnt++ работает только в CF11 и более поздних версиях, это и сравнение, и затем увеличение, но при этом сохраняется строка кода, предназначенная только для увеличения. До CF11, <cfset cnt=cnt+1><cfif cnt gt 5>...)   -  person gordon    schedule 28.04.2020


Ответы (5)


Начал это как комментарий, но быстро стал слишком длинным. Я обычно использую счетчик, как вы упомянули. Я не думаю, что у ColdFusion есть встроенный способ справиться с этим за вас. Если вас беспокоит только сравнение текущего значения с предыдущим значением, я делал что-то подобное раньше:

<cfset previousValue = "">
<cfloop array = #myarray# index = "value">
    <cfif mystruct[value] GT 5>
        <!--- do something --->
    </cfif> 
    <cfif value NEQ previousValue>
        <!--- do something --->
    </cfif>
    <cfset previousValue = value>
</cfloop>
person Miguel-F    schedule 13.06.2013
comment
+1, потому что это хороший шаг для борьбы с крайними случаями. просто нужно побеспокоиться о том, что проще ИМХО. - person Travis; 13.06.2013

Вы обнаружили недостаток в реализации зацикливания массива в ColdFusion: индекс/позиция в массиве просто недоступны.

Я поднял этот вопрос в Adobe, а также аналогичный сбой в arrayEach().

Обо всем этом понятии можно прочитать «интересное» на Блог Эндрю Скотта, где обсуждаются различные мнения (и различия в них).

Между прочим, Railo делает все это правильно, как я писал на мой собственный блог.

Суть в том, что вам нужно поддерживать свой собственный счетчик, как вы намекаете, и @Miguel-F подтверждает.

Голосуйте за ошибки... возможно, Adobe исправит их в ColdFusion 11...

person Adam Cameron    schedule 13.06.2013
comment
Похоже, они наконец-то реализовали его в 2016 году: tracker.adobe.com/#/view/CF. -3341256 - person Leigh; 06.02.2017

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

<cfloop from="1" to="#ArrayLen(myarray)#" index="i">
  <cfset value = myarray[i]>
  <cfif mystruct[value] GT 5>
    ... do something
  </cfif>
  <cfset lastIndex = i - 1>
  <cfif lastIndex AND value NEQ myarray[lastIndex]>
    ... do something
  </cfif>
</cfloop>
person Henry    schedule 13.06.2013
comment
Я думаю, что назвал бы переменную prevIndex, а не lastIndex, чтобы не запутаться на мгновение, поскольку это последний элемент массива. И если вы не хотите устанавливать переменную, которую будете использовать только один раз... <cfif (i-1) AND value NEQ myarray[lastIndex]> Очень хорошая переделка, с i-1 в качестве логического значения. - person gordon; 28.04.2020

Давайте подумаем об этом по-другому. Если мы перепишем их в cfscript для наглядности:

  myArray=[ 'xyz', 'yyy', '232', 'uoiu', 'youneedthis', '2343'];
    writedump(myArray);
    myLongStringThing = '';

    // LOOP OVER AN INDEX AND MANUALLY PUSH YOUR ARRAY ALONG
    for ( i = 1; i <= myArray.size(); i++) {
      v = myArray[i];
      if(i < 5 && i > 1 && myArray[i] != myArray[i-1]   ){
        x = doSomethingComplicated(v);
        myArray[i] = x; // Your new computed value
      }

      if(i > 1 && v != myArray[i-1] ) {
        y = somethingElseCool(v);
        myLongStringThing &= y;
      }
    }

    writedump(myArray);
    writeoutput(myLongStringThing & '<br>');

    // LOOP THE VALUES IN THE STRUCT/ARRAY 
    i = 0;
    for (k in myArray) {
      i++;
      writeoutput('k:' & k & '<br>');
      writeoutput('a[i]:' & myArray[i] & '<br>');
    }

    function doSomethingComplicated(v) {
      Arguments.v &= 'you did it!';
      return Arguments.v;
}

    function somethingElseCool(v) {
      Arguments.v &= ';';
      return Arguments.v;
    }

    // LOOPING A STRUCT IS DIFFERENT
    myStruct = {'asdf' = 234234, 'sdfsd' = 9798, 'oiujlkj3' = 'kohjkjh'};
    for (k in myStruct) {
      writeoutput('kinstruct:' & k & '<br>');
      writeoutput('kinstruct:' & myStruct[k] & '<br>');
    }

Если мы рассмотрим сигнатуру атрибута cfloop так же, как использование for(counter;condition;incrementor) и for(valuekey in object), мы увидим, что это примерно одно и то же.

Вы можете выбрать, как перебирать ваш объект (массив), но вы не можете выбрать версию только для значения, и текущие итераторы отслеживают индекс для вас.

Поэтому, если вам нужно отслеживать ваш предыдущий/следующий индекс, вам нужно выбрать метод итератора, который позволяет индекс (даже если это делается вручную).

NB: для массива вы, вероятно, можете смешивать/сопоставлять значение ключа с ручным итератором (стиль for(k in obj)), но когда используется структура, это фактическое имя KEY возвращается в 'k'. Не значение итерируемого массива. Это соответствует сигнатуре атрибута cfloop для зацикливания коллекции (например, структуры).

Я думаю, вы просите cfloop позволить вам установить маркер атрибута как значения, так и индекса. И я понимаю, что другие языки (и диалекты) могут это делать, но пока что в CF нет.

Пограничные случаи легко обрабатываются с помощью составного оператора if.

Вы можете использовать точно такую ​​же составную логику в операторах if в тегах, чтобы учитывать крайние случаи.

Вы могли заметить, что я использовал size() вместо ArrayLen(). Существует несколько операторов Java, которые можно использовать с массивами. Однако, насколько я могу судить, ни один из них не дает вам «курсор» или индекс данного состояния.

Если вы хотите еще немного углубиться в массивы, вы можете создать java-версию массива и сделать еще несколько вещей:

myArray = CreateObject( "java", "java.util.ArrayList" );
writeDump(myArray);  // This will show you the java object, which needs to be 'inited' still.
myArray = myArray.init(); // It returns the array, it does not act on the orig obj.
// You can now access the vast majority of java methods (including the parent methods)
myArray.add('myFirstValue');
myArray.add('my2ndValue');
myArray.add('yetAnotherValue');
writeDump(myArray);// This will look like a regular array dump
// You can also apply regular CF functions to this array like arrayAppend().
x = myArray.get(1); // This is a java index, so it begins at 0 which is the 1st elem. 1 is 2nd, etc.
writeOuput('At java index 1 we have:' & x & '<br>');

Вы можете поиграть с некоторыми из них, но насколько я могу судить, ни один из них не вернет пригодный для использования курсор или индекс. Однако некоторые из них могут оказаться полезными, например, subList() и equals().

В конечном счете, если вы хотите найти индекс без ручного индекса, вы можете сделать это:

index = arrayFind(myArray, v)

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

person williambq    schedule 14.06.2013

Если вы используете CF 10 или Railo 4, вы можете использовать each() из библиотека Underscore.cfc для цикла с индексом:

_ = new Underscore();

_.each(myArray, function (value, index) {
   // loop code here
});

Я бы предложил использовать более выразительную функцию, например map() или reduce(), в зависимости от того, что вы пытаетесь выполнить с помощью цикла.

Примечание: я написал Underscore.cfc

person Russ    schedule 16.06.2013