首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我的分类有什么问题?

我的分类有什么问题?
EN

Stack Overflow用户
提问于 2016-01-29 19:54:03
回答 3查看 403关注 0票数 6

首先,我必须指定我在Unity5.3中工作,而新的MonoDevelop不允许我进行调试。团结只会崩溃:

因此,我有一个“目标”清单,我需要根据三个标准进行排序:

  1. 首先要列出“积极”的目标。
  2. 然后按难度等级排序
  3. 最后随机获得相同级别的目标

以下是我的代码:

代码语言:javascript
复制
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;
    }
});

当我运行这段代码时,有时我会得到一个或多个非活动目标之后的活动目标,但我不明白为什么。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-01-29 22:36:42

要正确工作,排序算法不应依赖于变异状态。解释为什么在比较值时使用随机生成器不是一个好主意就在这里

这个问题可以通过两种方式来解决:

选项1:预先计算随机数

代码语言:javascript
复制
    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);

工作样品

选项2:排序然后洗牌

代码语言:javascript
复制
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;  
    }  
}           

工作样品

洗牌算法是从这里中借用的

票数 3
EN

Stack Overflow用户

发布于 2016-01-29 22:41:04

试试这个羔羊:

代码语言:javascript
复制
(a, b) => ((b.Active ? 1000 : 0) + b.Level) - ((a.Active ? 1000 : 0) + a.Level)

Active比1的级别差更重要1000倍,这对1000个级别是有效的。当Active是相同的,该级别就变得相关。最后,如果它仍然是相同的,它将以一种确定性的,但无关的方式,这是相同的随机。

没有必要使用真正的随机数。在一次运行中,顺序总是相同的,但在不同的运行过程中可能会有所不同。如果确实需要随机排序,可以使用以下命令:

代码语言:javascript
复制
(a, b) =>
    ((b.Active ? 10000 : 0) + b.Level * 10) -
    ((a.Active ? 10000 : 0) + a.Level * 10) + UnityEngine.Random.Range(-1, 2)
票数 0
EN

Stack Overflow用户

发布于 2016-01-30 02:23:56

我不能重复你的问题,得到“一个或多个积极的目标后,不积极的目标”。听起来您的Goal实例在排序之后发生了变异。我建议在可能的情况下尝试制作只读对象。

我的另一个建议是简化对代码的排序,使其更清晰、更易于推理--尽管在这种情况下,这可能没有直接帮助。

只需这样做:

代码语言:javascript
复制
var sorted =
(
    from g in goals
    orderby g.Active descending, g.Level, UnityEngine.Random.Range(-1, 2)
    select g
.ToList();

...or或者是类似于这样的:

代码语言:javascript
复制
var sorted =
    goals
        .OrderByDescending(g => g.Active)
        .ThenBy(g => g.Level)
        .ThenBy(g => rnd.Next())
        .ToList();

LINQ排序在随机源中工作得很好。我对它做了分布分析,它和费舍-耶茨一样有效。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35092917

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档