Reputation: 1396
I have a list class that implements IEnumerable<T>
.
Type T is a complex class with a string member as unique identifier. But it's enough to take just int as element type for explanations.
I want to move multiple items one step to left.
Example:
Original list: 0, 1, 2, 3, 4, 5
Now all bold items (0,3,4) should be moved to left (as far as possible).
Result list: 0, 1, 3, 4, 2, 5
Is there a good algorithm to do that? Maybe just with LINQ.
Edit: Answers for a List<T>
list are welcome. My class has similar methods. (Thanks for hint by TylerOhlsen.)
Edit2: One selected item should not pass another selected item.
Upvotes: 1
Views: 2212
Reputation: 5578
I didn't come up with a good way to use Linq, but here's a simple looping algorithm. If you can come up with a Sort function, that would be better. Or you could look at the Linq Zip method.
IList<int> myList = new List<int>(new[] {0, 1, 2, 3, 4, 5});
IList<int> moveLeftList = new List<int>(new[] {0, 1, 3, 4});
//Go through the original list in order and remove
// all items from the move left list until you reach
// the first item that is not going to be moved left.
//Items removed are already as far left as they can be
// so they do not need to be moved left and can therefore
// be safely removed from the list to be moved.
foreach (int item in myList)
{
int index = moveLeftList.IndexOf(item);
if (index >= 0)
moveLeftList.RemoveAt(index);
else
break;
}
foreach (int item in moveLeftList)
{
int index = myList.IndexOf(item);
//Dont move left if it is the first item in the list or it is not in the list
if (index <= 0)
continue;
//Swap with this item with the one to its left
myList.RemoveAt(index);
myList.Insert(index-1, item);
}
Upvotes: 2
Reputation: 50114
This looks like it works:
public static IEnumerable<T> MoveSelectedLeft<T>(
this IEnumerable<T> source,
IEnumerable<int> indicesToMove /* must be in order! */)
{
using (var itm = indicesToMove.GetEnumerator())
{
bool hasNextToMove = itm.MoveNext();
int nextToMove = hasNextToMove ? itm.Current : -1;
bool canMoveYet = false;
T held = default(T);
int currentIndex = 0;
foreach (T t in source)
{
if (hasNextToMove && nextToMove == currentIndex)
{
hasNextToMove = itm.MoveNext();
nextToMove = hasNextToMove ? itm.Current : -1;
yield return t;
}
else
{
if (!canMoveYet)
{
canMoveYet = true;
}
else
{
yield return held;
}
held = t;
}
currentIndex++;
}
if (canMoveYet)
yield return held;
}
}
called as
foreach (int i in new[] { 0,1,2,3,4,5 }.MoveSelectedLeft(new[] { 0,3,4 }))
{
Console.WriteLine(i);
}
Upvotes: 3
Reputation: 2564
You should use the "Sort" function for this and provide a custom comparer.
Take a look at this example.
Upvotes: 1
Reputation: 31194
Here's a description of an algorithm. store the element directly to leftof your group of elements(in this case a 2
) in a `temp variable.
starting at the leftmost element, move the elements to the left 1 by 1.
place the temp
variable to the right of where the group now is.
If you're using a linked list, it can be better. you just remove the 2
from where it is, and insert it to the right of the group.
Upvotes: 1