我有一個與此類似的嚴格要求:
struct Chunk
{
public float d; // distance from player
public bool active; // is it active
}
我有一個這個結構的陣列。
我需要的:
我需要對其進行排序,以便第一個元素是一個非活動塊,它也是離玩家最遠的塊,而不是下一個元素是活動的,也是最接近玩家的,這就是模式,
- 不活動,最遠
- 活躍的,最近的
- 不活動,最遠
- 活躍的,最近的
- 不活動的,最遠的等等......
目前我正在使用 LINQ,我正在這樣做:
chunk = chunk.AsParallel().OrderBy(x => x.active ? x.d : -x.d).ToArray();
但我不知道如何讓它一個接一個地交替。
uj5u.com熱心網友回復:
看起來您想將其拆分為兩個串列,對它們進行排序,然后將它們交錯。
var inactive = chunk.Where(x => !x.active).OrderByDescending(x => x.d);
var active = chunk.Where(x => x.active).OrderBy(x => x.d);
var interleaved = inactive.Zip(active, (a, b) => new [] { a, b }).SelectMany(x => x);
uj5u.com熱心網友回復:
但我不知道如何讓它一個接一個地交替。
如果您對陣列進行排序,使所有非活動都在開頭,降序,所有活動都在結尾,降序..
OrderBy(x => x.active?1:0).ThenBy(x=>-x.d)
然后你可以從一開始拿一個專案,然后從最后拿一個專案,然后從開始 1,然后到最后 - 1 向內作業
public static IEnumerable<Chunk> Interleave(this Chunk[] chunks){
for(int s = 0, e = chunks.Length - 1; s<e;){
if(!chunks[s].active)
yield return chunks[s ];
if(chunks[e].active)
yield return chunks[e--];
}
}
這里面有一點,所以讓我們打開它。這是一種作用于塊陣列的擴展方法。這是一個自定義列舉器方法,因此您可以呼叫 foreach 來使用它
foreach(var c in chunk.Interleave())
它包含一個跟蹤兩個變數的 for 回圈,一個用于開始索引,一個用于結束。開始遞增,結束遞減。在某個時候他們會相遇并且s不再小于e,這就是我們停止的時候:
for(int s = 0, e = chunks.Length - 1; s<e;){
我們需要在回傳之前查看塊,如果它在開始附近是非活動的,yield return它將開始增加一個。s increments s,但決議為s在它增加之前的值。因此,它在概念上就像chunks[s]; s = 1;在一個班輪中做
if(!chunks[s].active)
yield return chunks[s ];
然后我們查看接近結尾的塊,如果是active則回傳結尾塊并將結尾索引降低
不活動的塊由 跟蹤s,如果s到達活動塊,它將停止回傳(跳過回圈的每一次通過),這意味著e將向下作業,s只回傳活動塊
同樣,如果不活動的數量多于活動的數量,e將首先停止遞減,并將逐步s向上e
If you never came across yield return before think of it as a way to allow you to resume from where you left off rather than starting the method over again. It's used with enumerations to provide a way for the enumeration to return an item, then be moved on one and return the next item. It works a bit like saving your game and going doing something else, then coming back, realising your save game and carrying on from where you left off. Asking an enumerator for Next makes it load the game, play a bit, then save and stop.. Then you Next again and the latest save id loaded, play some more, save and stop. This way you gradually get through the game a bit at a time. If you started a new enumeration by calling Interleave again, that's like starting a new game over from the beginning
MSDN will get more detailed on yield return if you want to dig in more
Edit:
You can perform an in-place sort of your Chunk[] by having a custom comparer:
public class InactiveThenDistancedDescending : IComparer
{
public int Compare(object x, object y)
{
var a = (Chunk)x;
var b = (Chunk)y;
if(a.Active == b.Active)
return -a.Distance.CompareTo(b.Distance);
else
return a.Active.CompareTo(b.Active);
}
}
And:
Array.Sort(chunkArray, _someInstanceOfThatComparerAbove);
uj5u.com熱心網友回復:
不知道你是否可以只用一行代碼來做到這一點。
我寫了一個方法,只需要對陣列進行一次排序。然后,它根據 for 回圈的當前索引進入下一個最近或最遠的塊(奇數 = 最接近,偶數 = 最遠)。我從排序串列中洗掉該專案以確保它不會重新輸入到結果串列中。最后,我將結果作為陣列回傳。
public Chunk[] SortArray(List<Chunk> list_to_sort)
{
//Setup Variables
var results = new List<Chunk>();
int count = list_to_sort.Count;
//Tracking the sorting list so that we only need to sort the list once
list_to_sort = list_to_sort.OrderBy(x => x.active).ThenBy(x => x.d).ToList();
//Loop through the list
for (int i = 0; i < count; i )
{
results.Add(list_to_sort[i % 2 == 0 ? list_to_sort.Count - 1 : 0]);
list_to_sort.RemoveAt(i % 2 == 0 ? list_to_sort.Count - 1 : 0);
}
// Return Results
return results.ToArray();
}
可能有更好的方法來做到這一點,但希望它有所幫助。請注意,我沒有測驗這種方法。
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/427143.html
上一篇:在物體框架中查找多個OR引數
