Показать сообщение отдельно
Старый 23.11.2010, 01:40   #10  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от gl00mie Посмотреть сообщение
обожаемые мной Set'ы в Аксапте всегда отсортированы, так что там {1, 2} и {2, 1} тождественны.
М-м-м? Т.е. множества еще и упорядочены?

все равно что-то не то.
адаптировал метод класса в job'ик. плюс добавил человеческий вывод в инфолог.

задал множества {1,2} и {2,3}
получил срабатывание assert + странные результаты.
Нажмите на изображение для увеличения
Название: 1.PNG
Просмотров: 612
Размер:	83.9 Кб
ID:	6411

и все-таки: почему последовательно, а не в одной транзакции?
может все-таки добавить поле с новым значением, и тупо заменить у каждой записи?

X++:
/// <summary>
///     возвращает список пар [исходное значение, новое значение] для последовательной замены исходных значений на
///     новые таким образом, чтобы на любом шаге замены в изменяемом множестве значений не возникало дубликатов
///     может использоваться, к примеру, для перебивки значений поля таблицы, на котором висит уникальный индекс
/// </summary>
/// <param name="_setOfValues2Replace">
///     множество значений, подлежащих замене
///     должно быть непустым и иметь простой значимый (не ссылочный) базовый тип
/// </param>
/// <param name="_setOfNewValues">
///     множество новых значений, на которые надо заменить исходные
///     может полностью или частично пересекаться со значениями, подлежащими замене
///     должно иметь тот же базовый тип и число элементов, что и _setOfValues2Replace
/// </param>
/// <returns>
///     список контейнеров [исходное значение, новое значение] для последовательной замены в нужном порядке
///     либо пустой список, если замена невозможна (к примеру, множества исходных и новых значений тождественны)
/// </returns>
/// <remarks>
///     ACHTUNG!!! исходные множества изменяются!
/// </remarks>
/// <exception cref="Exception::Error">
///     выбрасывается, если входные параметры не соответствуют предусловиям
/// </exception>
static void DEV_getListOfValueReplacementPairs(Args args)
{
    Set _setOfValues2Replace = new Set(Types::Integer);
    Set _setOfNewValues = new Set(Types::Integer);

    Set         setOfUniqueNewValues;
    Set         setOfCommonValues;
    SetIterator setIterNew;
    SetIterator setIterOld;
    anytype     oldValue;
    anytype     newValue;
    Types       baseType;
    Counter     nElements;
    List        ret;
    ;
    //////////////////
    /**/
    _setOfValues2Replace.add(1);      _setOfNewValues.add(2);
    _setOfValues2Replace.add(2);      _setOfNewValues.add(1);
    /*
    _setOfValues2Replace.add(0);      _setOfNewValues.add(1);
    _setOfValues2Replace.add(1);      _setOfNewValues.add(2);
    _setOfValues2Replace.add(3);      _setOfNewValues.add(3);
    _setOfValues2Replace.add(7);      _setOfNewValues.add(4);
    _setOfValues2Replace.add(9);      _setOfNewValues.add(5);
    _setOfValues2Replace.add(15);     _setOfNewValues.add(6);
    _setOfValues2Replace.add(20);     _setOfNewValues.add(7);
    */

    //////////////////

    if (_setOfValues2Replace)
    {
        baseType    = _setOfValues2Replace.typeId();
        nElements   = _setOfValues2Replace.elements();
    }
    // проверка предусловий
    if (!(      _setOfNewValues
        &&      _setOfValues2Replace
        &&      nElements   >  0
        &&      nElements   == _setOfNewValues.elements()
        &&      baseType    == _setOfNewValues.typeId()
        &&  (   baseType    == Types::Date
            ||  baseType    == Types::Enum
            ||  baseType    == Types::Guid
            ||  baseType    == Types::Int64
            ||  baseType    == Types::Integer
            ||  baseType    == Types::Real
            ||  baseType    == Types::RString
            ||  baseType    == Types::String
            ||  baseType    == Types::Time
            ||  baseType    == Types::UtcDateTime
            ||  baseType    == Types::VarString
            )
       ))
    {
        throw error( Error::wrongUseOfFunction( funcname() ) );
    }
    ret = new List( Types::Container );
    setOfCommonValues = Set::intersection( _setOfValues2Replace, _setOfNewValues );
    if (setOfCommonValues.elements() < nElements)
    {
        if (!setOfCommonValues.empty())
        {
            setOfUniqueNewValues = Set::difference( _setOfNewValues, setOfCommonValues );
            setIterNew = new SetIterator( setOfUniqueNewValues );
            setIterOld = new SetIterator( setOfCommonValues );
            while (setIterNew.more())
            {
                if (!setIterOld.more())
                {
                    break;
                }
                oldValue = setIterOld.value();
                newValue = setIterNew.value();
                ret.addEnd( [ oldValue, newValue ] );
                _setOfNewValues.remove( newValue );
                _setOfValues2Replace.remove( oldValue );
                setOfUniqueNewValues.remove( newValue );
                if (_setOfNewValues.in( oldValue ))
                {
                    setOfUniqueNewValues.add( oldValue );
                    setIterNew.begin();
                }
                else
                {
                    setIterNew.next();
                }
                setIterOld.next();
            }
            Debug::assert( _setOfValues2Replace.elements() == setOfUniqueNewValues.elements() );
        }
        else
        {
            setIterNew = new SetIterator( _setOfNewValues );
        }
        // оставшиеся на замену значения никак не пересекаются с новыми
        setIterNew.begin();
        setIterOld = new SetIterator( _setOfValues2Replace );
        while (setIterNew.more() && setIterOld.more())
        {
            oldValue = setIterOld.value();
            newValue = setIterNew.value();
            ret.addEnd( [ oldValue, newValue ] );
            setIterNew.next();
            setIterOld.next();
        }
        Debug::assert( ret.elements() == nElements );
    }

    info(ret.definitionString());
    info(ret.xml());
}
__________________
полезное на axForum, github, vk, coub.

Последний раз редактировалось mazzy; 23.11.2010 в 02:06. Причина: поправил код согласно исправлениям gl00mie