Generic List - Moving an Item Within the List

Generic List - moving an item within the list

I know you said "generic list" but you didn't specify that you needed to use the List(T) class so here is a shot at something different.

The ObservableCollection(T) class has a Move method that does exactly what you want.

public void Move(int oldIndex, int newIndex)

Underneath it is basically implemented like this.

T item = base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, item);

So as you can see the swap method that others have suggested is essentially what the ObservableCollection does in it's own Move method.

UPDATE 2015-12-30: You can see the source code for the Move and MoveItem methods in corefx now for yourself without using Reflector/ILSpy since .NET is open source.

Move item to bottom of list using List.Move

Actually, this worked for me (I'm not sure why it wasn't working before). @prospector 's answer is probably also quite valid (just didn't work for my unique situation)

public object MoveLoopToBottom()
{
if (selectedLoops.Count < 1)
return null;

foreach (ProfilerLoop selected in selectedLoops)
{
int moveFrom = PartLoops.IndexOf(selected);

ClonedLoops.Move(moveFrom, PartLoops.Count - 1);
}

return null;
}

Move elements in list

list.Remove("Eve");  // Removes the first "Eve" element in the list
list.Insert(0, "Eve"); // Inserts "Eve" at the first position in the list

However, if your list contains multiple "Eve"s, calling Remove("Eve") will only remove the first occurrence of "Eve".

And you have to know that inserting element at the beginning of a list is an expensive operation. Because all elements already in the list have to be shifted.

UPDATE

As @AlvinWong commented, LinkedList<string> is a very good solution to avoid this overhead when inserting an element. The Insert operation is done in O(1) (O(n-i) in a List). The major drawback of LinkedList<string> is that accessing the ith element is an operation in O(i) (O(1) in a List).

How to move a subset of items in a list in c#?

You can use the following for this:

List<string> removedRange = l.GetRange(oldIndex, size);
l.RemoveRange(oldIndex, size);
l.InsertRange(newIndex, removedRange);

How do i move a list object at the end of the list while shifting back the others?

You're overthinking this.

var value = list[index];
list.RemoveAt(index);
list.Add(value);

change and update order of generic list items with C#

You need to make a contract where you can ensure the items you use have a property of int Order. Then restrict your function T type to be of your contract type.

public interface ISortable
{
int Id { get; set; }
int Order { get; set; }
}

public class Scenario : ISortable
{
public int Id { get; set; }
public int Order { get; set; }
public string Title { get; set; }
}

private void UpdateOrders<T>(T targetScenario, short newOrder, List<T> items) where T : ISortable
{
items = items.OrderBy(_ => _.Order).ToList();
bool seen = false;
for (int i = 0; i < items.Count; i++)
{
if (items[i].Id == targetScenario.Id)
{
items[i].Order = newOrder;
seen = true;
}
else if (seen)
{
if (items[i].Order <= newOrder)
{
items[i].Order--; // move it left
}
}
else
{
if (items[i].Order >= newOrder)
{
items[i].Order++; // move it right
}
}
}
}

C# Moving a section of items within the list

You can do this very generally for any IEnumerable using an iterator block relatively simply. I always find that using the yield return construct solves this type of problem in a clear and concise way. Here, I've also made the method into an extension method for ease of use:

public static class Extension
{
public static IEnumerable<T> MoveSection<T>(this IEnumerable<T> @this, int insertionPoint, int startIndex, int endIndex)
{
var counter = 0;
var numElements = endIndex - startIndex;
var range = Enumerable.Range(startIndex, numElements);
foreach(var i in @this)
{
if (counter == insertionPoint) {
foreach(var j in @this.Skip(startIndex).Take(numElements)) {
yield return j;
}
}
if (!range.Contains(counter)) {
yield return i;
}
counter++;
}
//The insertion point might have been after the entire list:
if (counter++ == insertionPoint) {
foreach(var j in @this.Skip(startIndex).Take(numElements)) {
yield return j;
}
}
}
}

Here I use the Linq methods Skip and Take, which are often useful. Also, you might be interested in the Enumerable.Range method, which allows for easy creation of the ranges like you do with a for loop instead.

You can then invoke the method like so:

myList.MoveSection(8, 1, 3);


Related Topics



Leave a reply



Submit