2016-01-29 21 views
6

Trước hết tôi phải xác định rằng tôi đang làm việc trong Unity 5.3 và MonoDevelop mới không cho phép tôi gỡ lỗi. Unity chỉ bị treo :(Điều gì xảy ra với phân loại của tôi?

Vì vậy, tôi có một danh sách các "mục tiêu" mà tôi cần phải sắp xếp dựa trên 3 tiêu chí:

  1. đầu tiên sẽ được liệt kê các mục tiêu "hoạt động"
  2. sau đó ra lệnh bằng khó khăn mức
  3. cuối cùng một cách ngẫu nhiên cho các mục tiêu của cùng một mức

đây là mã của tôi:

public class Goal { 
    public int ID; 
    public int Level; 
    public bool Active; 
} 

... 

List<Goal> goals; 

goals.Sort((a, b) => { 
    // first chooses the Active ones (if any) 
    var sort = b.Active.CompareTo(a.Active); 
    if (sort == 0) { 
     // then sort by level 
     sort = (a.Level).CompareTo(b.Level); 
     // if same level, randomize. Returns -1, 0 or 1 
     return sort == 0 ? UnityEngine.Random.Range(-1, 2) : sort; 
    } else { 
     return sort; 
    } 
}); 

Khi tôi chạy mã này đôi khi tôi nhận được một hoặc nhiều mục tiêu hoạt động sau những mục tiêu không hoạt động, nhưng tôi không hiểu tại sao.

+2

Bạn có thể thu hẹp hành vi đối với một bộ đầu vào cụ thể không? –

+0

Sự cố có thể liên quan đến thứ tự sắp xếp không phải là duy nhất. Đó là: bất kỳ lệnh nào * có thể * là chính xác, nhưng do ngẫu nhiên các mục có cùng mức độ ưu tiên, bất kỳ nỗ lực nào để xác minh đơn hàng này sẽ trả về một thứ tự khác. Tôi sẽ tìm một cách khác để xáo trộn mọi thứ – Draco18s

+0

Bạn có thể đưa ra một đầu vào mẫu sao chép (hoặc có cơ hội tái tạo) vấn đề không? –

Trả lời

3

Để hoạt động chính xác, thuật toán sắp xếp không được phụ thuộc vào trạng thái biến đổi trạng thái. Giải thích lý do tại sao sử dụng trình tạo ngẫu nhiên trong khi so sánh các giá trị không phải là ý tưởng hay is given here.

Vấn đề có thể được giải quyết bằng hai cách:

Lựa chọn 1: Pre-tính toán số ngẫu nhiên

var tmp = goals.Select(g=> new {goal = g, weight = rnd.NextDouble()}) 
     .OrderByDescending(t=>t.goal.Active) // Active first 
     .ThenBy(t=>t.goal.Level) 
     .ThenBy(t=>t.weight) 
     .Select(t=>t.goal) 
     .ToList(); 



    goals.Clear(); 
    goals.AddRange(tmp); 

Working sample

Lựa chọn 2: Sắp xếp sau đó xáo trộn quan hệ

Random rnd = new Random(); 

Comparison<Goal> comparison = (a, b) => { 
// first chooses the Active ones (if any) 
var sort = b.Active.CompareTo(a.Active); 

if (sort == 0) { 
// then sort by level 
    return sort = (a.Level).CompareTo(b.Level); 
    } else 
{ 
    return sort; 
} 
}; 



int startIndex = 0; 
int endIndex = 0; 

goals.Sort(comparison); 

while (startIndex < goals.Count) 
{ 
    for (endIndex = startIndex + 1; endIndex < goals.Count; ++endIndex) 
    { 
     if (comparison(goals[startIndex], goals[endIndex]) != 0) 
     { 
      //End of tie 
      break; 
     } 
    } 

    if (endIndex - startIndex > 1) 
    { 
     // Shuffle goals of the same level 
     ShuffleRange(goals, startIndex, endIndex - startIndex, rnd); 
    } 

    startIndex = endIndex; 
} 

static void ShuffleRange<T>(List<T> list, int startIndex, int count, Random rnd) 
{ 
    int n = startIndex + count; 
    while (n > startIndex + 1) 
    { 
     int k = rnd.Next(startIndex, n--); 
     T value = list[k]; 
     list[k] = list[n]; 
     list[n] = value; 
    } 
}   

Working sample

thuật toán ngẫu nhiên được vay mượn từ here

+0

Sự ngẫu nhiên của OP chỉ là sự phân loại các phần tử sâu hơn (sau khi chúng được gán thứ tự đúng dựa trên hoạt động và ưu tiên so với các mức ưu tiên khác), ở đâu nó không quan trọng. Không? – andeart

+0

Vui lòng thử mã OP. Nó hoạt động như OP dự định - thứ tự của các giá trị được đặt ngẫu nhiên giữa chúng là không liên quan. – andeart

+0

@andeart: OP tuyên bố cuối cùng rằng mã không _always_ hoạt động chính xác. – alexm

0

Hãy thử lambda này:

(a, b) => ((b.Active ? 1000 : 0) + b.Level) - ((a.Active ? 1000 : 0) + a.Level) 

tích cực là quan trọng hơn 1000 lần so với một sự khác biệt mức độ 1. Điều này làm cho lên đến 1000 các cấp. Khi Active là như nhau, mức độ trở nên có liên quan. Cuối cùng, nếu nó vẫn là như nhau, nó sẽ được sắp xếp theo một cách xác định nhưng không liên quan, giống như ngẫu nhiên.

Không cần sử dụng số ngẫu nhiên thực sự. Thứ tự sẽ luôn giống nhau trong một lần chạy, nhưng nó có thể khác nhau giữa các lần chạy. Nếu bạn thực sự cần một thứ tự ngẫu nhiên bạn có thể sử dụng này:

(a, b) => 
    ((b.Active ? 10000 : 0) + b.Level * 10) - 
    ((a.Active ? 10000 : 0) + a.Level * 10) + UnityEngine.Random.Range(-1, 2) 
0

tôi không thể tái tạo vấn đề của bạn nhận được "một hoặc tích cực hơn các mục tiêu sau khi những người không hoạt động". Có vẻ như các trường hợp Goal của bạn đang bị tắt sau khi sắp xếp. Tôi sẽ đề nghị cố gắng tạo ra các đối tượng chỉ đọc nếu có thể.

Đề xuất khác của tôi là đơn giản hóa bạn sắp xếp mã để làm cho nó rõ ràng hơn và dễ dàng hơn để lý do - mặc dù đó có thể sẽ không trực tiếp trợ giúp trong trường hợp này.

Chỉ cần làm loại này:

var sorted = 
(
    from g in goals 
    orderby g.Active descending, g.Level, UnityEngine.Random.Range(-1, 2) 
    select g 
.ToList(); 

...hoặc cách khác và tương tự như thế này:

var sorted = 
    goals 
     .OrderByDescending(g => g.Active) 
     .ThenBy(g => g.Level) 
     .ThenBy(g => rnd.Next()) 
     .ToList(); 

LINQ sắp xếp hoạt động tốt với nguồn ngẫu nhiên. Tôi đã thực hiện phân tích phân phối trên nó và nó hoạt động cũng như các ngư dân.

Các vấn đề liên quan