Как мне удалить повторяющиеся значения из массива Coldfusion?

#arrays #coldfusion #duplicates

#массивы #coldfusion #дубликаты

Вопрос:

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

this.tags = listToArray(this.tags, ", ");

Как мне удалить повторяющиеся значения в случае, если таковые имеются?

Комментарии:

1. Абстрактный тип данных «set», доступный в Java, специально разработан для решения такого рода проблем.

Ответ №1:

Мне нравится использовать Java для такого рода задач:

 <cfset tags = "apples,oranges,bananas,pears,apples" />

<cfset tagsArray = createObject("java", "java.util.ArrayList").init(
createObject("java", "java.util.HashSet").init(ListToArray(tags))
) />

<cfdump var="#tags#" />
<cfdump var="#tagsArray#" />
  

Единственная проблема в том, что он учитывает регистр, поэтому считает, что «яблоки» и «APPLES» — это разные вещи (что технически да, в зависимости от вашей системы вполне может отличаться). Обходной путь заключается в том, чтобы сначала ввести все в списке в нижний регистр. (ПРИМЕЧАНИЕ: Добавлена java.util.ArrayList функция, позволяющая идентифицировать массив и повторно использовать его с помощью Adobe ColdFusion; в противном случае такие функции, как arraysort , выдадут ошибку.)

Комментарии:

1. спасибо за это. Вы проводили какое-либо тестирование / знаете, насколько это быстрее, чем зацикливать значения в структуре ColdFusion?

2. @Mohamad — С точки зрения скорости, я предполагаю, что HashSet быстрее. Но .. если вы не имеете дело с огромными списками, различия обычно невелики. Обычно я выбираю метод, который выполняет правильную работу, и беспокоюсь о скорости, только если это становится проблемой.

3. прелесть этого решения в том, что оно занимает ОДНУ СТРОКУ! В моем случае мне нужно было выяснить, имеет ли конкретное поле в запросе coldfusion более одного уникального значения. В то время как другие решения, описанные здесь, могли бы сработать, этот вкладыш сделал мой код очень простым: if (ArrayLen(createObject("java", "java.util.HashSet").init(cfQuery[colName]).toArray()) GT 1)

4. Джейсон, спасибо за код. После извлечения данных из другой системы у меня есть массив структур, которые имели повторяющиеся значения. Я смог передать массив через HashSet и в конечном итоге получить набор массивов, не содержащий дубликатов.

5. Я обновил пример, включив его java.util.ArrayList на основе примера здесь barneyb.com/barneyblog/2008/05/08/use-coldfusion-use-java в противном случае «массив» нельзя было бы повторно использовать как массив CFML.

Ответ №2:

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

Если порядок элементов важен, вам нужно будет создать массив вручную, а не использовать функцию listToArray.

 <!--- CF9 --->
<cfset tags = "apples,oranges,bananas,pears,APPLES" />
<cfset tagArray = arrayNew(1) />

<cfloop list="#tags#" index="tag" delimiters=",">
    <cfif not ArrayFindNoCase(tagArray,tag)>
        <cfset arrayAppend(tagArray, tag) />
    </cfif>
</cfloop>
  

Ответ №3:

Поскольку вы действительно начинаете со строки / списка, который затем преобразуете в массив, вы можете передать строку через ListRemoveDuplicates перед преобразованием в массив. ListRemoveDuplicates был введен в Coldfusion 10; входные параметры (list, delimiter=»,», IgnoreCase=FALSE).

 this.tags = listToArray(listRemoveDuplicates(arrayInput,", ",TRUE));
  

Если бы вы на самом деле начинали с массива, вам нужно было бы сначала преобразовать его в список, а затем обратно.

 this.tags = listToArray(listRemoveDuplicates(arrayToList(arrayInput),", ",TRUE) );
  

Комментарии:

1. Дампы кода не являются ответами. Пожалуйста, отредактируйте свой ответ и объясните, что это за код, как он работает и как он отвечает на вопрос.

2. Я бы сказал, что код говорит сам за себя. Просто прочитайте это, и будет ясно, что происходит.

3. Подсказка: ListRemoveDuplicates добавлено в ColdFusion 10. Не пытайтесь использовать его в более ранних версиях.

Ответ №4:

основано на идее Джейсона Хариту, но вы можете сделать это в чистом CF, используя Struct! (сопоставление ключей будет нечувствительным к регистру)

 this.tags = listToArray(this.tags, ", ");
var tmpStruct = {};

for (var t in this.tags)
    tmpStruct[t] = "";

return structKeyArray(tmpStruct);
  

Однако для небольших списков я предпочитаю решение Antony.

Комментарии:

1. просто любопытно, зачем беспокоиться о операторе if? Структуры никоим образом не допускают дублирования значений, так что не является ли использование условия здесь немного избыточным?

Ответ №5:

В Coldfusion 10 или Railo 4 вы могли бы использовать функцию uniq() подчеркивания.cfc:

 _ = new Underscore();

uniqueArray = _.uniq(arrayWithDuplicates);
  

Одним из преимуществ uniq() является то, что он позволяет при необходимости передавать функцию преобразования.

Примечание: Я написал подчеркивание.cfc

Ответ №6:

Мне просто пришлось удалить очень большой список (более 5 тысяч записей) и я нашел гораздо более быстрый способ, чем использование цикла. Я чувствую необходимость поделиться.

  1. преобразовать список в массив (у вас уже есть массив, поэтому пропустите) <cfset thisArray = ListToArray(thisList)>
  2. Создайте запрос с помощью queryNew(«») <cfset thisQuery = QueryNew("")>
  3. Добавьте столбец в этот запрос с помощью массива из шага 1 <cfset temp = QueryAddColumn(thisQuery,"items","varChar",thisArray)>
  4. Запрашивать разные значения <cfquery name="qItems" dbtype="query">SELECT DISTINCT items FROM thisQuery</cfquery>
  5. преобразовать результат в список <cfset returnString = ValueList(qItems.items)>
  6. Вам не составит труда преобразовать этот список обратно в массив

Я записал это в функцию для удобства использования:

 <cffunction name="deDupList" output="no" returntype="string">
    <cfargument name="thisList" required="yes">
    <cfargument name="thisDelimeter" required="yes" default=",">
    <cfset var loc = StructNew()>

    <cfset loc.thisArray = ListToArray(thisList,thisDelimeter)>
    <cfset loc.thisQuery = QueryNew("")>
    <cfset loc.temp = QueryAddColumn(loc.thisQuery,"items","varChar",loc.thisArray)>
    <cfquery name="qItems" dbtype="query">
        SELECT DISTINCT items FROM loc.thisQuery
    </cfquery>
    <cfset loc.returnString = ValueList(qItems.items)>
    <cfreturn loc.returnString>
</cffunction>
  

Я сравнил его с несколькими другими методами, и вот результаты в миллисекундах:
Циклическая проверка списка на наличие > 1 экземпляра: 6265
Используя метод Генри struct: 2969
Приведенный выше метод: 31
Метод Джейсона: 30

Комментарии:

1. (Редактировать) Я мог видеть, насколько медленным будет цикл. Но я очень удивлен, что вы сказали, что метод Джейсона был медленным, т.е. при использовании HashSet . Для меня это быстро упрощается с более чем 10 Тыс. элементов. Я даже схитрил и передал результаты обратно в вектор, чтобы порадовать CF.

2. Я перепутал свой скрипт для разметки, когда внедрял метод Джейсона, глупая ошибка. Вы правы, он работает чертовски быстро, исправил мои контрольные результаты. Спасибо.

3. Спасибо. Я бы, вероятно, выбрал HashSet . Но интересно, что QoQ выполняется быстрее, чем я ожидал.

Ответ №7:

Развивая ответ Джейсона чуть дальше, вот arrayDistinct функция.

 function arrayDistinct (required array data) {
    var output = arrayNew(1);
    output.addAll(createObject("java", "java.util.HashSet").init(arguments.data));
    return output;
}
  

Вы можете протестировать это здесь: https://trycf.com/gist/62ff904d4500519e3144fc9564d2bce7/acf

Ответ №8:

Просто поместите массив в структуру, а затем скопируйте его обратно в массив 😉

http://www.bennadel.com/blog/432-Using-ColdFusion-Structures-To-Remove-Duplicate-List-Values.htm

Ответ №9:

Я публикую еще одно удобное решение, которое мне нравится.

 arrayReduce(arrayWithDuplicates, function(resultArr, item) {
   if(!arrayFind(resultArr, item)){
      arrayAppend(resultArr, item);
   }
   return resultArr;
}, [])
  

ArrayReduce доступно с ColdFusion 11.

Но чтобы лучше ответить на вопрос, из ColdFusion 10 у нас есть ListRemoveDuplicates функция, доступная.

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

 this.tags = listToArray(listRemoveDuplicates(this.tags, ", "), ", ");
  

Ответ №10:

В CFLib есть пара UDF, которые делают это, ArrayyDiff (http://www.cflib.org/udf/arrayDiff ) и arrayCompare (http://www.cflib.org/udf/arrayCompare ).

привет, Ларри