I am working on a algorithm which will solve a problem I have, but I am finding myself a little stuck. Here is the scenario:
I have an object which contains a variable called order.
public class Item
{
public int Order{get; set;};
public int ID{get; set;}; // not incremented can be any value!
}
So I have a list of these:
List<Item> list = new List<Item>().OrderBy((o) => o.Order);
And at any time the order value can be changed. So if I want to change the first an items order value all other order values should update accordingly so there are no duplicates.
for (int i = 0; i <= list .Count - 1; i++)
{
if (list [i].ID == inputID)
{
list [i].Order = inputNewPosition;
}
else
{
if (list [i].Order < inputNewPosition)
{
list [i].Order --;
}
else
{
list [i].Order ++;
}
}
}
This fails if I change the last item order to be the first, as this would make the first item order be 0!
Can anyone help?
Thanks
Let us look at the four situations for an element in your list (as we iterate through them). If (for terseness) we take old
to be the item that is moving's old position and new
to be its new position we have the following cases for an item in your list (draw them out on paper to make this clear).
- the current item is the one to be moved: move it directly
- the current item's order is <
new
and <old
: don't move it - the current item's order is ≥
new
and <old
: move it right - the current item's order is ≤
new
and >old
: move it left - the current item's order is >
new
and >old
: don't move it
When we start enumerating, we know the where the item to be moved will end up (at new
) but we do not know where it has come from (old
). However, as we start our enumeration at the beginning of the list, we know at each step that it must be further down in the list until we have actually seen it! So we can use a flag (seen
) to say whether we have seen it yet. So seen
of false means < old
whilst true means >= old
.
bool seen = false;
for (int i = 0; i < items.Length; i++)
{
if (items[i].ID == inputID)
{
items[i].Order = inputNewPosition;
seen = true;
}
}
This flag tells us whether the current item is >= old. So now can start shunting stuff around based on this knowledge and the above rules. (So new
in the above discussion is inputNewPosition
and whether we are before or after old
we represent with our seen
variable.)
bool seen;
for (int i = 0; i < items.Count; i++)
{
if (items[i].ID == inputID) // case 1
{
items[i].Order = inputNewPosition;
seen = true;
}
else if (seen) // cases 4 & 5
{
if (items[i].Order <= inputNewPosition) // case 4
{
items[i].Order--; // move it left
}
}
else // case 2 & 3
{
if (items[i].Order >= inputNewPosition) // case 3
{
items[i].Order++; // move it right
}
}
}
Having said all of that, it is probably simpler to sort the collection on each change. The default sorting algorithm should be quite nippy with a nearly sorted collection.