我正在尝试根据第一次出现的值重新组织一个数组(从而模拟与圆形数组类似的功能。)
例如,在下面的数组中,我希望第一次出现的值6成为新的第一个元素,而先前的元素成为后者:
所以:
int[] myArray = {2, 3, 6, 1, 7, 6};
成为:
myArray = {6, 1, 7, 6, 2, 3};
实现这一目标的“最佳”方式是什么?
答案 0 :(得分:19)
int[] myArray = { 2, 3, 6, 1, 7, 6 };
myArray = myArray
.SkipWhile(i => i != 6)
.Concat(myArray.TakeWhile(i => i != 6))
.ToArray();
应该做的伎俩!
您需要使用System.Linq
;
答案 1 :(得分:9)
Thorsten的解决方案创建了一个新阵列;这是一个就地版本,它只创建一个与旋转大小一样大的临时数组:
public static void RotateLeft<T>(T[] array, int places)
{
T[] temp = new T[places];
Array.Copy(array, 0, temp, 0, places);
Array.Copy(array, places, array, 0, array.Length - places);
Array.Copy(temp, 0, array, array.Length - places, places);
}
我确定可以只用一个临时缓冲项来完成,但它会更复杂:)
作为效率衡量标准,这里是“向左转一个地方”的捷径:
public static void RotateLeft<T>(T[] array)
{
T temp = array[0];
Array.Copy(array, 0, array, 1, array.Length - 1);
array[array.Length-1] = temp;
}
答案 2 :(得分:5)
您可以执行以下操作:
Array.Copy()
复制从开始索引到源数组末尾到目标数组Array.Copy()
复制从0到源阵列的起始索引到目标数组末尾的所有内容通过这种方式,您可以获得与预期相符的源数组副本。
但是,您必须使用Array.Copy()
的各种重载,因为我现在还不知道确切的参数值。
答案 3 :(得分:5)
首先,进行线性搜索,找到您想要成为第一个元素的第一个值:
// value contains the value to find.
int skip;
for (int i = 0; i < array.Length; i++)
{
if (array[i] == value)
{
skip = i;
break;
}
}
// skip contains the index of the element to put at the front.
// Equivalently, it is the number of items to skip.
// (I chose this name for it because it makes the subtractions
// in the Array.Copy implementation more intuitive.)
你想改变实际的阵列吗?然后做Thorsten Dittmar建议的事情:
int[] array = new int[] { 2, 3, 6, 1, 7, 6 };
int[] result = new int[array.Length];
int skip = 2; // So that array[skip] will be result[0] at the end
Array.Copy(array, skip, result, 0, array.Length - skip);
Array.Copy(array, 0, result, array.Length - skip, skip);
您是否只想以新的顺序查看数组,而不做其他任何事情?然后将其编入索引:
array[(i + skip) % array.Length] // Instead of array[i]
编辑:仅仅是为了笑,Jon Skeet建议在仅使用单个缓冲区值(sourceValue
)的情况下实现副本:
// GCD gives the greatest common divisor
int gcd = GCD(array.Length, skip);
// period is the length of the permutation cycles in our rotation.
int period = array.Length / gcd;
int max = array.Length / period;
for (int i = 0; i < max; i++)
{
int sourceIndex = i;
int sourceValue = array[sourceIndex];
for (int n = 1; n <= period; n++)
{
int destinationIndex = (sourceIndex + array.Length - skip) % array.Length;
int temp = array[destinationIndex];
array[destinationIndex] = sourceValue;
sourceValue = temp;
sourceIndex = destinationIndex;
}
}
答案 4 :(得分:3)
作为创建新数组的替代方法,您可以使用类包装它:
class CircularList<T> : IList<T>
{
static IEnumerable<T> ToEnumerator(CircularList<T> list)
{
for (int i = 0; i < list.Count; i++)
{
yield return list[i];
}
}
IList<T> arr;
public int Shift { get; private set; }
public CircularList(IList<T> arr, int shift)
{
this.arr = arr;
this.Shift = shift;
}
int shiftIndex(int baseIndex)
{
return (baseIndex + Shift) % arr.Count;
}
#region IList<T> Members
public int IndexOf(T item) { throw new NotImplementedException(); }
public void Insert(int index, T item) { throw new NotImplementedException(); }
public void RemoveAt(int index) { throw new NotImplementedException(); }
public T this[int index]
{
get { return arr[shiftIndex(index)]; }
set { arr[shiftIndex(index)] = value; }
}
#endregion
#region ICollection<T> Members
public void Add(T item) { throw new NotImplementedException(); }
public void Clear() { throw new NotImplementedException(); }
public bool Contains(T item) { throw new NotImplementedException(); }
public void CopyTo(T[] array, int arrayIndex) { throw new NotImplementedException(); }
public int Count { get { return arr.Count; } }
public bool IsReadOnly { get { throw new NotImplementedException(); } }
public bool Remove(T item) { throw new NotImplementedException(); }
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return ToEnumerator(this).GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ToEnumerator(this).GetEnumerator();
}
#endregion
}
这个程序:
class Program
{
static void Main(string[] args)
{
int[] myArray = { 2, 3, 6, 1, 7, 6 };
CircularList<int> circularList =
new CircularList<int>(myArray, Array.IndexOf<int>(myArray, 6));
foreach (int i in circularList)
{
Console.WriteLine(i);
}
}
}
打印以下内容:
6 1 7 6 2 3
答案 5 :(得分:0)
var ar = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
ar = ar.SkipWhile(a => a != 6).ToArray<int>();
答案 6 :(得分:0)
C#答案: 输入:{1,2,3,5,6,7,8}; 输出:{8,7 1,2,3,5,6};
{
static void Main(string[] args)
{
int[] array = { 1, 2, 3, 5, 6, 7, 8 };
int index = 2;
int[] tempArray = new int[array.Length];
array.CopyTo(tempArray, 0);
for (int i = 0; i < array.Length - index; i++)
{
array[index + i] = tempArray[i];
}
for (int i = 0; i < index; i++)
{
array[i] = tempArray[array.Length -1 - i];
}
}
}
答案 7 :(得分:0)
新方法仅适用于.NET 4.5(2012年起)或更高版本:
const int value = 6;
int[] myArray = { 2, 3, 6, 1, 7, 6, };
var index = Array.IndexOf(myArray, value);
if (index == -1)
throw new InvalidOperationException();
var rotatedArray = (new ArraySegment<int>(myArray, index, myArray.Length - index))
.Concat(new ArraySegment<int>(myArray, 0, index))
.ToArray();
在早期的.NET版本中,ArraySegment<>
值无法像IEnumerable<>
一样用作{。}}。
我不清楚是否要求对原始数组实例进行变异,但如果需要,只需附加:
rotatedArray.CopyTo(myArray, 0);
到我的代码。