Ваш код верен с точки зрения точности (десятичная дробь не теряет точности при инвертировании знака).Его скорость можно уверенно повысить в 20 раз, записав его с помощью циклов и выполнив полное внешнее объединение вручную.Однако я рекомендовал бы это, только если perf критичен, потому что это увеличит размер кода в 5 раз.
Редактировать: объединение слиянием означает одновременное получение двух отсортированных списков и обход по обоим спискам таким образом,элементы могут быть найдены, даже если в обоих массивах есть лишние элементы.Это расширение шага слияния в сортировке слиянием.Полный-внешний означает, что он означает в базах данных: сохраняйте значения, которые есть только в одном из массивов.
Единственное требование, отсортированные списки, является заданным, поскольку вы сортируете список результатов.Ваш код будет работать следующим образом:
var results = new List<decimal>(input.Select(x => x*100 ));
results.Sort();
var listA = new List<decimal>();
var listB = new List<decimal>();
//now to the merge-join and fill listA and B
Объединение слиянием будет сложно реализовать, но для начала вот версия на основе итератора, которую я использую в своем проекте для объединения двух гигантскихфайлы, которые я никогда не смог бы загрузить в память, но которые отсортированы.
public static IEnumerable<TResult> MergeJoin_OneToOne<TLeft, TRight, TResult>(
IEnumerable<TLeft> leftCollection,
IEnumerable<TRight> rightCollection,
Func<TLeft, TRight, int> comparison,
Func<TLeft, TResult> onlyLeftSelector,
Func<TRight, TResult> onlyRightSelector,
Func<TLeft, TRight, TResult> bothSelector)
{
return MergeJoin_OneToOne_Impl(leftCollection, rightCollection, comparison, onlyLeftSelector, onlyRightSelector, bothSelector);
}
static IEnumerable<TResult> MergeJoin_OneToOne_Impl<TLeft, TRight, TResult>(
IEnumerable<TLeft> leftCollection,
IEnumerable<TRight> rightCollection,
Func<TLeft, TRight, int> comparison,
Func<TLeft, TResult> onlyLeftSelector,
Func<TRight, TResult> onlyRightSelector,
Func<TLeft, TRight, TResult> bothSelector)
{
if (leftCollection == null) throw new ArgumentNullException("leftCollection");
if (rightCollection == null) throw new ArgumentNullException("rightCollection");
if (comparison == null) throw new ArgumentNullException("comparison");
if (onlyLeftSelector == null) throw new ArgumentNullException("onlyLeftSelector");
if (onlyRightSelector == null) throw new ArgumentNullException("onlyRightSelector");
if (bothSelector == null) throw new ArgumentNullException("bothSelector");
using (var leftEnum = leftCollection.GetEnumerator())
using (var rightEnum = rightCollection.GetEnumerator())
{
if (!leftEnum.MoveNext())
{
while (rightEnum.MoveNext()) yield return onlyRightSelector(rightEnum.Current);
yield break;
}
if (!rightEnum.MoveNext())
{
do
{
yield return onlyLeftSelector(leftEnum.Current);
} while (leftEnum.MoveNext());
yield break;
}
while (true)
{
int cmp = comparison(leftEnum.Current, rightEnum.Current);
if (cmp == 0)
{
yield return bothSelector(leftEnum.Current, rightEnum.Current);
if (!leftEnum.MoveNext())
{
while (rightEnum.MoveNext())
{
yield return onlyRightSelector(rightEnum.Current);
}
yield break;
}
if (!rightEnum.MoveNext())
{
do
{
yield return onlyLeftSelector(leftEnum.Current);
} while (leftEnum.MoveNext());
yield break;
}
}
else if (cmp < 0)
{
yield return onlyLeftSelector(leftEnum.Current);
if (!leftEnum.MoveNext())
{
do
{
yield return onlyRightSelector(rightEnum.Current);
} while (rightEnum.MoveNext());
yield break;
}
}
else
{
yield return onlyRightSelector(rightEnum.Current);
if (!rightEnum.MoveNext())
{
do
{
yield return onlyLeftSelector(leftEnum.Current);
} while (leftEnum.MoveNext());
yield break;
}
}
}
}
}
По соображениям производительности вы специализируете эту функцию для IList<decimal>
элементов.Выбери материал итератора и используй два целых, чтобы представить текущую позицию в списке.При ходьбе listA игнорировать элементы с lt 0 и одинаковыми для B.
Повышение скорости будет происходить благодаря множеству улучшений: распределение объектов значительно сокращено;Операции хеширования, выполняемые Except, исчезли;Никаких лямбд и косвенных указаний.