#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 тысяч записей) и я нашел гораздо более быстрый способ, чем использование цикла. Я чувствую необходимость поделиться.
- преобразовать список в массив (у вас уже есть массив, поэтому пропустите)
<cfset thisArray = ListToArray(thisList)>
- Создайте запрос с помощью queryNew(«»)
<cfset thisQuery = QueryNew("")>
- Добавьте столбец в этот запрос с помощью массива из шага 1
<cfset temp = QueryAddColumn(thisQuery,"items","varChar",thisArray)>
- Запрашивать разные значения
<cfquery name="qItems" dbtype="query">SELECT DISTINCT items FROM thisQuery</cfquery>
- преобразовать результат в список
<cfset returnString = ValueList(qItems.items)>
- Вам не составит труда преобразовать этот список обратно в массив
Я записал это в функцию для удобства использования:
<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 ).
привет, Ларри