Home > Software engineering >  Elegant way to rotate items inside of array or list in c#?
Elegant way to rotate items inside of array or list in c#?

Time:02-16

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.

CodePudding user response:

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);
}

CodePudding user response:

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

CodePudding user response:

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.

  • Related