'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 |
