5

I am using a List construct to handle the sequence in which images are drawn in "OnPaint". Now if my images are re-ordered (e.g. "brought to front" or "..to back"), I'd need to reposition them in my List. I have trouble doing so, because List doesn't support a method similar to setIndex().

So what I am trying to do is basically:

    private List<BitmapWithProps> activeImages = new List<BitmapWithProps>();

    public void addActiveImage(BitmapWithProps image)
    {
        activeImages.Add(image);
    }

    public BitmapWithProps getActiveImage(int index)
    {
        return activeImages[index];
    }

    public void removeActiveImage(int index)
    {
        activeImages.RemoveAt(index);
    }

    public void removeActiveImage(BitmapWithProps item)
    {
        activeImages.Remove(item);
    }

    public void swapActiveImageIndex(int sourceIndex, int destIndex)
    {
        // what would the code look like in here if I were to swap
        // the 2nd item (1) with the 4th one (3) in a 5-item-List (0 - 4)
    }

I want to be able to swap an index.. sort of. I could "insert" a new item into the List at the index it should go to and assign the value and then delete the other "source". However it doesn't seem elegant in any way.

I'd be glad for any hints and please excuse me if I overlooked a thread - I did search though, before asking.

dS.

3 Answers 3

8

What's inelegant about doing the steps you want to do? If you want to change something's position within a List (which is a vector style collection) then what you want to do is insert it at the new position and remove it from the old. Precisely what you are complaining about having to do.

If it really upsets you then write an extension method:

public static void MoveIndex<T>(this List<T> list, int srcIdx, int destIdx)
{
  if(srcIdx != destIdx)
  {
    list.Insert(destIdx, list[srcIdx]);
    list.RemoveAt(destIdx < srcIdx ? srcIdx + 1 : srcIdx);
  }
}

Edit: Oh, you just want to swap? Simpler (and more efficient) still:

public static void SwapItems<T>(this List<T> list, int idxX, int idxY)
{
  if(idxX != idxY)
  {
    T tmp = list[idxX];
    list[idxX] = list[idxY];
    list[idxY] = tmp;
  }
}
8
  • Thank you. I actually already thought about inserting/removing, but I thought there's a better way, like really .. swap or something. On the other hand - your method does precisely what I want to do. Now I only need to figure out how to add this method as an extension to the List :). Thank you +vote up.
    – Igor
    Commented Aug 22, 2010 at 22:37
  • I've added swapping too If those methods are put in a static class "visible" to the calling code, then activeImages.MoveIndex(1, 3) or activeImages.SwapItems(1, 3) will do the appropriate thing in C#3 or higher. C#2 or lower, you need to either get rid of the "this" and call them as static methods, or just do the same operations the methods have.
    – Jon Hanna
    Commented Aug 22, 2010 at 22:40
  • Note that the swap method should be preferred, because it is O(1) whereas List<T>.Insert and List<T>.RemoveAt are both O(n). They may have to move remaining elements in the list up and down, to keep the immediate list well-defined (but you actually just care about the final result).
    – ollb
    Commented Aug 22, 2010 at 22:58
  • Ah. Thanks for this hint, Gnafoo. That's why I asked for help, because else I might have implemented a method that actually works, but is not "elegant" and thus needs more time to finish.
    – Igor
    Commented Aug 22, 2010 at 23:12
  • Yep, swapping beats moving where appropriate. However when not appropriate (you move the first item to the fourth position) then doing that by a series of swaps is also O(n) though for a smaller n, and has more expensive constants, so I'd go for the direct approach unless lists were likely to be very large, or the move in a loop.
    – Jon Hanna
    Commented Aug 22, 2010 at 23:12
2

Well, just performing a swap is easy:

BitmapWithProps source = activeImages[sourceIndex];
BitmapWithProps dest = activeImages[destIndex];
activeImages[destIndex] = source;
activeImages[sourceIndex] = dest;

But if you need to move one item and leave all other items in the same order with relation to each other, you should call RemoveAt followed by Insert. It won't be terribly efficient, but unless you've got a large list or you're doing this very often, it's unlikely to really cause you any problems.

0
public void swapActiveImageIndex(int sourceIndex, int destIndex)
{
    var source = activeImages.Item[sourceIndex];
    var dest = activeImages.Item[destIndex];

    activeImages.Item[sourceIndex] = dest;
    activeImages.Item[destIndex] = source;
}

Not the answer you're looking for? Browse other questions tagged or ask your own question.