Цитата:
Сообщение от
gl00mie
обожаемые мной Set'ы в Аксапте всегда отсортированы, так что там {1, 2} и {2, 1} тождественны.
М-м-м? Т.е. множества еще и упорядочены?
все равно что-то не то.
адаптировал метод класса в job'ик. плюс добавил человеческий вывод в инфолог.
задал множества {1,2} и {2,3}
получил срабатывание assert + странные результаты.
и все-таки: почему последовательно, а не в одной транзакции?
может все-таки добавить поле с новым значением, и тупо заменить у каждой записи?
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());
}