|  10.01.2014, 19:09 | #1 | 
| Участник | Сортировка контейнеров 
			
			Всегда не хватало сортировки контейнеров в DAX. Только руки дошли написать. Навеяно http://gatesasbait.wordpress.com/200...n-a-container/ можно указывать несколько полей для сортировки (контейнер индексов). X++: //class Global static container quickSort( container _qsc, container _cIndexKey = [1], int _qsstart = 1, int _qsend = conlen(_qsc) ) { int qsi = _qsstart; int qsj = _qsend; container qsx; container qsKey; boolean less(container _c1, container _c2) { int qsk; int idx; ; for (qsk=1; qsk<=conlen(_cIndexKey); qsk++) { idx = conpeek(_cIndexKey, qsk); if (conpeek(_c1, idx) < conpeek(_c2, idx)) return true; if (conpeek(_c1, idx) > conpeek(_c2, idx)) return false; } return false; } ; qsx = conpeek(_qsc, (_qsstart +_qsend)/2); do { qsKey = conpeek(_qsc, qsi); while (less(qsKey, qsx)) { qsi++; if (qsi <= conlen(_qsc)) { qsKey = conpeek(_qsc, qsi); } else { break; } } qsKey = conpeek(_qsc, qsj); while (less(qsx, qsKey)) { qsj = qsj - 1; if (qsi > 0) { qsKey = conpeek(_qsc, qsj); } else { break; } } if (qsi <= qsj) { qsKey = conpeek(_qsc, qsi); _qsc = conpoke(_qsc, qsi, conpeek(_qsc, qsj)); _qsc = conpoke(_qsc, qsj, qsKey); qsi++; qsj = qsj - 1; } } while (qsi <= qsj); if (_qsstart < qsj) { _qsc = Global::quickSort(_qsc, _cIndexKey, _qsstart, qsj); } if (qsi < _qsend) { _qsc = Global::quickSort(_qsc, _cIndexKey, qsi, _qsend); } return _qsc; } X++: container c = [ [2, 3], [5, 2], [1, 2], [20, 2], [10, 2] ]; c = quickSort(c, [2,1]); //[ [1, 2], [5, 2], [10, 2], [20, 2], [2, 3] ] c = quickSort(c); //[ [1, 2], [2, 3], [5, 2], [10, 2], [20, 2] ] | 
|  | |
| За это сообщение автора поблагодарили: S.Kuskov (3). | |
|  10.01.2014, 22:33 | #2 | 
| Участник | 
			
			А, если не секрет, зачем это?..   . В Аксапте есть классы-коллекции, поддерживающие сортировку, - Set и Map, если нужно сортировать данные, то лучше, мне кажется, использовать их. Скажем, если есть контейнер значений одного базового типа, то получить их в отсортированном по возрастанию виде можно так: X++: container conValues = ...;
Types baseType = typeof(conpeek(conValues, 1));
Set setOfValues = Set::create([1, any2int(baseType), conlen(conValues)] + conValues);Последний раз редактировалось gl00mie; 10.01.2014 в 22:57. Причина: очепятка | 
|  | 
|  10.01.2014, 23:45 | #3 | 
| Участник | 
			
			Позвольте позанудствовать, но для реального использования не самая лучшая реализация, а для разминки или задачки на собеседовании вполне себе.
		 
				__________________ Sapere aude Последний раз редактировалось Diman; 10.01.2014 в 23:46. Причина: typo | 
|  | 
|  11.01.2014, 02:32 | #4 | 
| Участник | 
			
			Иногда возникает необходимость отсортировать мизерный набор данных (до 10 строк), но не простые типы, а кортежи. Задача "не заслуживает" отдельной временной таблицы. Вот для этих целей и создавался метод. В моём случае это были контейнер из 2 элементов (лот и некое несопоставленное кол-во по лоту). Сортировал по кол-ву и подбирал нужный лот. Свою задачу я решил. Производительность устраивает. Ничего подобного в базовом фунционале не нашёл.
		 | 
|  | |
| За это сообщение автора поблагодарили: mazzy (2). | |
|  11.01.2014, 12:07 | #5 | 
| Участник | 
			
			0. в алгоритме есть принципиальная ошибка - конейнер может содержать другие контейнеры. а также другие объекты, для которых отсутствует операция сравнения. поэтому ваш алгоритм имеет очень ограниченное применение. надо отдать должное функция less - прикольная.  но потенциально опасна runtime-ошибками. 1. насколько я помню (пусть меня поправят знающие люди), контейнер - это атомарный объект в Аксапте. другими словами, при любой попытке изменения контейнера, фактически происходит пересоздание контейнера. со всеми вытекающими последствиями. насколько я помню, именно это и послужило причиной создания объектов-коллекций и причиной неразвития таких полезных структур как KeySum. 2. контейнер - чисто аксаптовская структура, для которой нет аналога ни на .net., ни в SQL, ни в OLAP... в связи с планами перевода всего и вся на .net, контейнеры будут все более более неприемлемым инструментом. поэтому: 
 ================================= в связи с вышесказанным лучше: * преобразовать контейнер в объект-коллекцию, например в set, (при преобразовании выполните проверку) * (опционально для несортирующих коллекций) выполнить сортировку * преобразовать объект-коллекцию обратно в контейнер. причем в классе Global вроде уже есть функции преобразователи. и если содержимое контейнера вам заранее известно и не требует проверки и не содержит одинаковых элементов, то лучше вместо своего алгоритма вызвать пару функций, что-то вроде X++: myContainer = set2con(con2set(myContainer)); // сортируем контейнер, содержащий индексыПоследний раз редактировалось mazzy; 11.01.2014 в 12:27. | 
|  | 
|  11.01.2014, 12:24 | #6 | 
| Участник | 
			
			теперь по существу алгоритма. 1. использовать во вложенной функции less переменную _cIndexKey, глобальную по отношению к функции less - безусловный моветон. 2. мне кажется, что будут проблемы с пустыми контейнерами (поскольку _cIndexKey и _qsstart инициализируются единицей) 3. вместо вычисления conlen в цикле по неизменному контейнеру, лучше один раз вычислить и хранить в переменной. поскольку conlen каждый раз просматривает контейнер и вычисляет. 4. и мне кажется... что будут серьезные проблемы, если контейнер будет содержать одинаковые элементы. например, как мне кажется (аксапты нет под рукой чтобы проверить), будет неправильно отсротирован такой контейнер [ [1, 1], [10,10], [1,1], [5,5], [1,1] ] В общем: * за попытку - зачет * но по реализации - Дональд Кнут в помощь Последний раз редактировалось mazzy; 11.01.2014 в 12:29. | 
|  | 
|  11.01.2014, 13:15 | #7 | 
| Участник | Цитата: Цитата: Сделал дополнительную проверку на пустой контейнер Цитата: Цитата: Попутно доделал возможность указывать порядок сортировки для каждого элемента. Исправленная версия: X++: static container quickSort( container _qsc, container _cIndexKey = [[1, SortOrder::Ascending]], int _qsstart = 1, int _qsend = conlen(_qsc) ) { int qsi = _qsstart; int qsj = _qsend; container qsx; container qsKey; boolean less(container _c1, container _c2) { int qsk; int idx; SortOrder so; int len = conlen(_cIndexKey); ; for (qsk=1; qsk<=len; qsk++) { [idx, so] = conpeek(_cIndexKey, qsk); if (conpeek(_c1, idx) < conpeek(_c2, idx)) return (so==SortOrder::Ascending)?true:false; if (conpeek(_c1, idx) > conpeek(_c2, idx)) return (so==SortOrder::Ascending)?false:true; } return false; } ; if (! conlen(_qsc)) return _qsc; qsx = conpeek(_qsc, (_qsstart +_qsend)/2); do { qsKey = conpeek(_qsc, qsi); while (less(qsKey, qsx)) { qsi++; if (qsi <= conlen(_qsc)) { qsKey = conpeek(_qsc, qsi); } else { break; } } qsKey = conpeek(_qsc, qsj); while (less(qsx, qsKey)) { qsj = qsj - 1; if (qsi > 0) { qsKey = conpeek(_qsc, qsj); } else { break; } } if (qsi <= qsj) { qsKey = conpeek(_qsc, qsi); _qsc = conpoke(_qsc, qsi, conpeek(_qsc, qsj)); _qsc = conpoke(_qsc, qsj, qsKey); qsi++; qsj = qsj - 1; } } while (qsi <= qsj); if (_qsstart < qsj) { _qsc = Global::quickSort(_qsc, _cIndexKey, _qsstart, qsj); } if (qsi < _qsend) { _qsc = Global::quickSort(_qsc, _cIndexKey, qsi, _qsend); } return _qsc; } X++: container c = [ [1, 2], [10,10], [1,5], [5,5], [1,10] ]; ; c = global::quickSort(c, [[1, SortOrder::Descending],[2, SortOrder::Ascending]]); // [ [10,10], [5,5], [1, 2], [1,5], [1,10] ] | 
|  | |
| За это сообщение автора поблагодарили: mazzy (5), alex55 (3). | |
|  11.01.2014, 14:52 | #8 | 
| Участник | 
			
			Спасибо за конструктивный подход. Цитата: Согласно вашей функции less, кортежи [1,2], [1,5], [1,10] - это разные элементы. я же говорил об одинаковых элементах [1,1], [1,1], [1,1]. посмотрю чуть позже, когда доберусь до аксапты. | 
|  | 
|  11.01.2014, 16:06 | #9 | 
| Участник | 
			
			Одинаковые кортежи тоже нормально отсортировались. Новый пример привел для демонстрации управления порядком сортировки
		 | 
|  | 
|  12.01.2014, 19:25 | #10 | 
| Участник | Цитата: спасибо. на маленьких контейнерах заданной структуры вполне можно использовать. тем более, что функций con2set, set2con в стандарте нет. и к тому же вы добавили порядок сортировки. =================== маленькое дополнение на будущее: = в качестве значения по умолчанию используйте литералы = в качестве значения по умолчанию никогда НЕ используйте потенциально-долго-выполняющиеся функции, вместо них используйте prmisdefault Дело в том, что Аксапта ВСЕГДА вычисляет значение по умолчанию. Даже если значение было передано в вызывающем классе. X++: static container quickSort( container _qsc, container _cIndexKey = [[1, SortOrder::Ascending]], int _qsstart = 1, int _qsend = 0 ) { int _qsend = prmisdefault(_qsend) ? conlen(_qsc) : _qsend; ... но в целом - контейнеры лучше не использовать.   | 
|  | 
|  13.01.2014, 08:49 | #11 | 
| Участник | Цитата: AX2009: X++:     boolean defaultValue()
    {
        ;
        info("!");
        return true;
    }
    
    void test(boolean _prm = defaultValue())
    {
        ;
        info(strfmt("%1", _prm));
    }
    ;
    
    test();
    test(true);
    test(false);Цитата: 
		
			! true true false | 
|  | |
| За это сообщение автора поблагодарили: mazzy (5). | |
|  13.01.2014, 09:57 | #12 | 
| Участник | |
|  | 
|  13.01.2014, 17:21 | #13 | 
| Участник | 
			
			есть еще системный класс KeySum
		 | 
|  | 
|  14.01.2014, 17:51 | #14 | 
| Участник | |
|  | 
|  15.01.2014, 15:41 | #15 | 
| Участник | 
			
			Об этом уже говорили: Цитата: Всё же придерживаюсь мнения использовать классы-коллекции для сортировки. 
				__________________ // no comments | 
|  |