C #에서 목록을 회전하는 가장 쉬운 방법
목록에 목록이 있다고 표시됨 List<int> {1,2,3,4,5}
회전은 다음을 의미합니다.
=> {2,3,4,5,1} => {3,4,5,1,2} => {4,5,1,2,3}
회전이 가장 좋은 단어는 아니지만 제가 의미하는 바를 이해하시기 바랍니다.
내 질문, 가장 쉬운 방법은 무엇입니까 (짧은 코드에서 C # 4 Linq 준비 됨), 성능 (합리적 성능)에 타격을받지 않을 것입니다.
감사.
큐로 구현할 수 있습니다. 동일한 값을 대기열에서 빼고 대기열에 넣습니다.
** 목록을 대기열로 변환하는 성능에 대해 확신 할 수 없었지만 사람들이 내 댓글에 찬성 투표를했기 때문에 답변으로 게시했습니다.
가장 간단한 방법은 (A의 List<T>
)를 사용하는 것입니다 :
int first = list[0];
list.RemoveAt(0);
list.Add(first);
성능은 좋지 않습니다-O (n).
정렬
이것은 기본적으로 List<T>
버전 과 동일 하지만 더 수동입니다.
int first = array[0];
Array.Copy(array, 1, array, 0, array.Length - 1);
array[array.Length - 1] = first;
LinkedList<T>
대신 a 를 사용할 수 있다면 훨씬 간단합니다.
int first = linkedList.First;
linkedList.RemoveFirst();
linkedList.AddLast(first);
각 작업이 일정 시간이므로 이것은 O (1)입니다.
큐를 사용하는 cadrell0의 솔루션은 Dequeue
요소 를 제거 하고 반환하므로 단일 명령문입니다 .
queue.Enqueue(queue.Dequeue());
이것의 성능 특성에 대한 문서를 찾을 수는 없지만 배열과 인덱스를 "가상 시작점"으로 사용하여 구현 될 것으로 예상 Queue<T>
됩니다.이 경우 이것은 또 다른 O (1) 솔루션입니다.
이 모든 경우에 목록이 비어 있는지 먼저 확인해야합니다. (오류 또는 작동하지 않는 것으로 간주 할 수 있습니다.)
나는 이것을 사용한다 :
public static List<T> Rotate<T>(this List<T> list, int offset)
{
return list.Skip(offset).Concat(list.Take(offset)).ToList();
}
일부 응답자는 이것을 데이터 구조를 탐색 할 기회로 취급 한 것 같습니다. 이러한 답변은 유익하고 유용하지만 Linq'ish는 아닙니다.
Linq'ish 접근 방식은 다음과 같습니다. 원하는 것을 빌드하는 방법을 알고있는 게으른 IEnumerable을 반환하는 확장 메서드를 얻습니다. 이 방법은 소스를 수정하지 않으며 필요한 경우에만 소스의 사본을 할당해야합니다.
public static IEnumerable<IEnumerable<T>> Rotate<T>(this List<T> source)
{
for(int i = 0; i < source.Length; i++)
{
yield return source.TakeFrom(i).Concat(source.TakeUntil(i));
}
}
//similar to list.Skip(i-1), but using list's indexer access to reduce iterations
public static IEnumerable<T> TakeFrom<T>(this List<T> source, int index)
{
for(int i = index; i < source.Length; i++)
{
yield return source[i];
}
}
//similar to list.Take(i), but using list's indexer access to reduce iterations
public static IEnumerable<T> TakeUntil<T>(this List<T> source, int index)
{
for(int i = 0; i < index; i++)
{
yield return source[i];
}
}
다음으로 사용 :
List<int> myList = new List<int>(){1, 2, 3, 4, 5};
foreach(IEnumerable<int> rotation in myList.Rotate())
{
//do something with that rotation
}
이건 어때:
var output = input.Skip(rot)
.Take(input.Count - rot)
.Concat(input.Take(rot))
.ToList();
rot
회전 할 지점의 수는 어디 입니까? input
목록 의 요소 수보다 작아야 합니다.
@ cadrell0 답변은 이것이 목록으로 수행하는 모든 작업인지 보여 주므로 목록 대신 대기열을 사용해야합니다.
내 솔루션은 LINQ'ish가 아니라 너무 기본적 일 수 있습니다 (절름발이라고 말하고 싶지 않습니다 ...).
그러나 그것은 꽤 좋은 성능을 가지고 있습니다.
int max = 5; //the fixed size of your array.
int[] inArray = new int[5] {0,0,0,0,0}; //initial values only.
void putValueToArray(int thisData)
{
//let's do the magic here...
Array.Copy(inArray, 1, inArray, 0, max-1);
inArray[max-1] = thisData;
}
시험
List<int> nums = new List<int> {1,2,3,4,5};
var newNums = nums.Skip(1).Take(nums.Count() - 1).ToList();
newNums.Add(nums[0]);
비록 나는 Jon Skeet의 대답을 더 좋아합니다.
어레이에 대한 내 솔루션 :
public static void ArrayRotate(Array data, int index)
{
if (index > data.Length)
throw new ArgumentException("Invalid index");
else if (index == data.Length || index == 0)
return;
var copy = (Array)data.Clone();
int part1Length = data.Length - index;
//Part1
Array.Copy(copy, 0, data, index, part1Length);
//Part2
Array.Copy(copy, part1Length, data, 0, index);
}
왼쪽 회전에는 아래 코드를 사용할 수 있습니다.
List<int> backUpArray = array.ToList();
for (int i = 0; i < array.Length; i++)
{
int newLocation = (i + (array.Length - rotationNumber)) % n;
array[newLocation] = backUpArray[i];
}
.net 프레임 워크에서 멋지게 플레이 할 수 있습니다.
나는 당신이 원하는 것이 새로운 컬렉션 유형보다 반복 동작에 달려 있다는 것을 이해합니다. 따라서 컬렉션, 목록 등에서 작동하는 IEnumerable을 기반으로이 확장 방법을 시도해 보는 것이 좋습니다.
class Program
{
static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7 };
IEnumerable<int> circularNumbers = numbers.AsCircular();
IEnumerable<int> firstFourNumbers = circularNumbers.Take(4); // 1 2 3 4
IEnumerable<int> nextSevenNumbersfromfourth = circularNumbers
.Skip(4).Take(7); // 4 5 6 7 1 2 3
}
}
public static class CircularEnumerable
{
public static IEnumerable<T> AsCircular<T>(this IEnumerable<T> source)
{
if (source == null)
yield break; // be a gentleman
IEnumerator<T> enumerator = source.GetEnumerator();
iterateAllAndBackToStart:
while (enumerator.MoveNext())
yield return enumerator.Current;
enumerator.Reset();
if(!enumerator.MoveNext())
yield break;
else
yield return enumerator.Current;
goto iterateAllAndBackToStart;
}
}
- 합리적인 성능
- 융통성 있는
더 나아가 려면 샘플 에서처럼 회전 할 때 CircularList
건너 뛰기 위해 동일한 열거자를 만들고 유지합니다 Skip()
.
이를 위해 다음 확장을 사용했습니다.
static class Extensions
{
public static IEnumerable<T> RotateLeft<T>(this IEnumerable<T> e, int n) =>
n >= 0 ? e.Skip(n).Concat(e.Take(n)) : e.RotateRight(-n);
public static IEnumerable<T> RotateRight<T>(this IEnumerable<T> e, int n) =>
e.Reverse().RotateLeft(n).Reverse();
}
그들은 확실히 쉬우 며 (OP 제목 요청) 합리적인 성능을 가지고 있습니다 (OP 쓰기 요청). 다음은 평균 이상으로 구동되는 랩톱에서 LINQPad 5로 실행 한 간단한 데모입니다.
void Main()
{
const int n = 1000000;
const int r = n / 10;
var a = Enumerable.Range(0, n);
var t = Stopwatch.StartNew();
Console.WriteLine(a.RotateLeft(r).ToArray().First());
Console.WriteLine(a.RotateLeft(-r).ToArray().First());
Console.WriteLine(a.RotateRight(r).ToArray().First());
Console.WriteLine(a.RotateRight(-r).ToArray().First());
Console.WriteLine(t.ElapsedMilliseconds); // e.g. 236
}
아래는 내 접근 방식입니다. 감사합니다
public static int[] RotationOfArray(int[] A, int k)
{
if (A == null || A.Length==0)
return null;
int[] result =new int[A.Length];
int arrayLength=A.Length;
int moveBy = k % arrayLength;
for (int i = 0; i < arrayLength; i++)
{
int tmp = i + moveBy;
if (tmp > arrayLength-1)
{
tmp = + (tmp - arrayLength);
}
result[tmp] = A[i];
}
return result;
}
public static int[] RightShiftRotation(int[] a, int times) {
int[] demo = new int[a.Length];
int d = times,i=0;
while(d>0) {
demo[d-1] = a[a.Length - 1 - i]; d = d - 1; i = i + 1;
}
for(int j=a.Length-1-times;j>=0;j--) { demo[j + times] = a[j]; }
return demo;
}
Linq를 사용하여
List<int> temp = new List<int>();
public int[] solution(int[] array, int range)
{
int tempLength = array.Length - range;
temp = array.Skip(tempLength).ToList();
temp.AddRange(array.Take(array.Length - range).ToList());
return temp.ToArray();
}
최소한의 메모리 사용으로 문자 배열을 뒤집도록 요청 받았습니다.
char[] charArray = new char[]{'C','o','w','b','o','y'};
방법:
static void Reverse(ref char[] s)
{
for (int i=0; i < (s.Length-i); i++)
{
char leftMost = s[i];
char rightMost = s[s.Length - i - 1];
s[i] = rightMost;
s[s.Length - i - 1] = leftMost;
}
}
모듈 식 산술을 사용하는 방법 :
public void UsingModularArithmetic()
{
string[] tokens_n = Console.ReadLine().Split(' ');
int n = Convert.ToInt32(tokens_n[0]);
int k = Convert.ToInt32(tokens_n[1]);
int[] a = new int[n];
for(int i = 0; i < n; i++)
{
int newLocation = (i + (n - k)) % n;
a[newLocation] = Convert.ToInt32(Console.ReadLine());
}
foreach (int i in a)
Console.Write("{0} ", i);
}
So basically adding the values to the array when I am reading from console.
참고URL : https://stackoverflow.com/questions/9948202/easiest-way-to-rotate-a-list-in-c-sharp
'Development Tip' 카테고리의 다른 글
두 필드 값으로 PHP 정렬 배열 (0) | 2020.11.26 |
---|---|
.bashrc에 추가 파일 포함 (0) | 2020.11.26 |
지도 조각 API v2 레이아웃 상단에 버튼을 추가하는 방법 (0) | 2020.11.26 |
쿼리 문자열 매개 변수가있는 node.js http 'get'요청 (0) | 2020.11.26 |
Visual Studio 2015 RTM-디버깅이 작동하지 않음 (0) | 2020.11.26 |