'Elegant way to rotate items inside of array or list in c#?

This is a general array question but, for my case, it is a list of strings.

Given: [a, b, c, d, e, f, g, h] and an item inside of the collection, say f.

Output: [f, g, h, a, b, c, d, e]

I can use substring methods or things like .take and .skip. But are there any cleaner alternatives like using linq or something else I might be unaware of?

edit: Okay, I apologize that I did not write question correctly. When I say LINQ, I meant something involving lambda expressions? Thanks for your comments. I will just stick with take and skip.



Solution 1:[1]

The Take() and Skip() methods are part of the LINQ. I do not see how you could rearrange the items inside the list via LINQ without using these methods.

List<string> list = new List<string>() { "a", "b", "c", "d", "e", "f", "g", "h", "i" };
string character = "f";
int i = list.IndexOf(character);

if (i != -1)
{
  list = list.Skip(i).Concat(list.Take(i)).ToList();
}

You could also use List specific methods like below

List<string> list = new List<string>() { "a", "b", "c", "d", "e", "f", "g", "h", "i" };
string character = "f";
int i = list.IndexOf(character);

if (i != -1)
{
   var sublist = list.GetRange(i, list.Count - i);
   list.RemoveRange(i, list.Count - i);
   list.InsertRange(0, sublist);
}

Solution 2:[2]

If you don't mind creating a new List or array, you can use an extension method (for IEnumerable<T>) to rotate the items and then create the collection you want.

// num - return items starting with numth item and wrapping around
//       e.g. rotate items so that numth item is first
public static IEnumerable<T> Rotate<T>(this IEnumerable<T> items, int num) {
    if (num > 0)
        if (items is IList<T> itemList) {
            for (int j1 = 0; j1 < itemList.Count; ++j1)
                yield return itemList[(j1+num) % itemList.Count];
        }
        else
            using (var itemsEnum = items.GetEnumerator()) {
                var q = new Queue<T>();

                while (itemsEnum.MoveNext() && num-- > 0)
                    q.Enqueue(itemsEnum.Current);

                do {
                    yield return itemsEnum.Current;
                } while (itemsEnum.MoveNext());

                while (q.Count > 0)
                    yield return q.Dequeue();
            }
}

With this extension method, you can do

var ans = src.Rotate(src.IndexOf("f")).ToList(); // or .ToArray()

If you want to do this with no additional object creation, you can use this answer instead.

Solution 3:[3]

another possibility

var newlist = new List<string>(oldList.Count);
newList.Add("f");
newList.AddRange(oldList.Where(x=>x!="f"));

less efficeint since it keeps looking at the elements even after its found the target one, but the code is simple

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 HSBogdan
Solution 2 NetMage
Solution 3 pm100