Не существует Swap-метода, поэтому вы должны создать его самостоятельно.Конечно, вы можете связать его, но это нужно делать с одним (неписанным?) Правилом: LINQ-операции не изменяют входные параметры!
В других ответах «linqify» (вход) список изменен и возвращен, но это действие нарушает это правило.Если было бы странно, если у вас есть список с несортированными элементами, выполните операцию LINQ "OrderBy" и обнаружите, что входной список также отсортирован (как результат).Этого не должно быть!
Итак ... как нам это сделать?
Моей первой мыслью было просто восстановить коллекцию после того, как она закончила итерацию.Но это грязное решение, поэтому не используйте его:
static public IEnumerable<T> Swap1<T>(this IList<T> source, int index1, int index2)
{
// Parameter checking is skipped in this example.
// Swap the items.
T temp = source[index1];
source[index1] = source[index2];
source[index2] = temp;
// Return the items in the new order.
foreach (T item in source)
yield return item;
// Restore the collection.
source[index2] = source[index1];
source[index1] = temp;
}
Это грязное решение, потому что изменяет список ввода, даже если он восстанавливаетэто в исходное состояние.Это может вызвать несколько проблем:
- Список может быть доступен только для чтения, что вызовет исключение.
- Если список используется несколькими потоками, список изменится для других потоков во время выполнения этой функции.
- Если во время итерации возникает исключение, список не будет восстановлен,(Это можно решить, написав try-finally внутри Swap-функции и поместив код восстановления в блок finally).
Существует лучшее (и более короткое) решение: простосделайте копию оригинального списка.(Это также позволяет использовать IEnumerable в качестве параметра вместо IList):
static public IEnumerable<T> Swap2<T>(this IList<T> source, int index1, int index2)
{
// Parameter checking is skipped in this example.
// If nothing needs to be swapped, just return the original collection.
if (index1 == index2)
return source;
// Make a copy.
List<T> copy = source.ToList();
// Swap the items.
T temp = copy[index1];
copy[index1] = copy[index2];
copy[index2] = temp;
// Return the copy with the swapped items.
return copy;
}
Одним из недостатков этого решения является то, что оно копирует весь список, который будет использовать память, и это делает решениедовольно медленно
Вы могли бы рассмотреть следующее решение:
static public IEnumerable<T> Swap3<T>(this IList<T> source, int index1, int index2)
{
// Parameter checking is skipped in this example.
// It is assumed that index1 < index2. Otherwise a check should be build in and both indexes should be swapped.
using (IEnumerator<T> e = source.GetEnumerator())
{
// Iterate to the first index.
for (int i = 0; i < index1; i++)
yield return source[i];
// Return the item at the second index.
yield return source[index2];
if (index1 != index2)
{
// Return the items between the first and second index.
for (int i = index1 + 1; i < index2; i++)
yield return source[i];
// Return the item at the first index.
yield return source[index1];
}
// Return the remaining items.
for (int i = index2 + 1; i < source.Count; i++)
yield return source[i];
}
}
И если вы хотите ввести параметр, равный IEnumerable:
static public IEnumerable<T> Swap4<T>(this IEnumerable<T> source, int index1, int index2)
{
// Parameter checking is skipped in this example.
// It is assumed that index1 < index2. Otherwise a check should be build in and both indexes should be swapped.
using(IEnumerator<T> e = source.GetEnumerator())
{
// Iterate to the first index.
for(int i = 0; i < index1; i++)
{
if (!e.MoveNext())
yield break;
yield return e.Current;
}
if (index1 != index2)
{
// Remember the item at the first position.
if (!e.MoveNext())
yield break;
T rememberedItem = e.Current;
// Store the items between the first and second index in a temporary list.
List<T> subset = new List<T>(index2 - index1 - 1);
for (int i = index1 + 1; i < index2; i++)
{
if (!e.MoveNext())
break;
subset.Add(e.Current);
}
// Return the item at the second index.
if (e.MoveNext())
yield return e.Current;
// Return the items in the subset.
foreach (T item in subset)
yield return item;
// Return the first (remembered) item.
yield return rememberedItem;
}
// Return the remaining items in the list.
while (e.MoveNext())
yield return e.Current;
}
}
Swap4 также делает копию (aподмножество) источника.В худшем случае, он такой же медленный и занимает много памяти, как функция Swap2.