【问题标题】:How to get a random order on a array.orderby C#如何在array.orderby C#上获取随机顺序
【发布时间】:2019-12-05 17:20:58
【问题描述】:

我正在尝试从数组中找到最接近集合整数的整数,但如果有多个整数,我想随机选择一个。

var nearestScore = scoreArray.OrderBy(x => Math.Abs((long)x - realScore)).First();

除了使用First(),我不知道任何其他方式。

我也试过了

var r = new random()
var nearestScore = scoreArray.OrderBy(x => Math.Abs((long)x - realScore)).ToArray();
return nearestScore[r.next(0, nearestScore.Length - 1)]

谢谢。

【问题讨论】:

  • 需要更多说明
  • 这毫无意义。如果您的输入是 100,并且数组中有 97、98 和 99,则 99 是 only 最接近的数字。如果有重复的 99 个条目,为什么要随机选择一个?
  • @ThePerplexedOne 如果输入是 98 并且值是 9997,则有两个“最近”值。
  • 好点@RufusL

标签: c# arrays .net


【解决方案1】:

您可以为此使用GroupBy()。对于小型数组来说,这有点笨拙但很简单。

Random rnd = new Random();

var nearestScore = scoreArray
    .Select(x => new { Num = x, Delta = Math.Abs((long)x - realScore)) })
    .OrderBy(a => a.Delta)
    .GroupBy(a => a.Delta)
    .First()
    .OrderBy(a => rnd.Next())
    .Select(a => a.Num)
    .First();

【讨论】:

  • 每次您通过rnd.Next() 订购时,都会有人勒死一只小狗。
  • @JoelCoehoorn:有没有一种你更喜欢的技术来公平地生成随机排列?
  • @JoelCoehoorn:您说“但主要是,我的理解是通过 rnd.Next() 进行排序的可能性很小(中奖很小,但仍然)没有完成或导致异常的机会.” 你记错了。 OrderBy 随机值总是安全的。 OrderBy 相当于创建一个值数组和一个键数组,然后按键对值数组进行排序。您可能在想的是,通过创建一个随机决定 X 是大于、等于还是小于 Y 的 比较器 来尝试洗牌总是错误
  • @JoelCoehoorn:总是错误的原因是比较器要求遵循规则:X 总是等于 X,如果 X 小于 Y,则 Y 是大于 X,并且决不存在传递性悖论;也就是说,如果 X 小于 Y 并且 Y 小于 Z,则 X 必须小于 Z。随机比较器不符合此约定,并可能导致排序算法以任意错误的方式失败。
  • @EricLippert:new Guid() 返回00000000-0000-0000-0000-000000000000。我猜你的意思是Guid.NewGuid()
【解决方案2】:

用几句话来打破它:

var minScore = scoreArray.Min(x => Math.Abs((long)x - realScore));
var list = scoreArray.Where(x => Math.Abs((long)x - realScore) == minScore).ToList();
// or you can use GroupBy with OrderBy and First instead of above, but this is lighter and cleaner
r = new Random();
var myRandomNumber = r.Next(0, list.Count);
return list[myRandomNumber];

【讨论】:

  • 我不能这样做,因为在后面的代码中,我必须这样做:int indexWinner = Array.IndexOf(scoreArray, nearestScore);
  • 仅供参考,您不需要减去 1,因为 maxValue 参数是独占的,我认为您的意思是从 list 中选择索引,而不是 scoreArray。您可以通过将最后 3 行替换为 return list[new Random().Next(list.Count)]; 来简化
  • 更正了 -1 和 `list' - 谢谢!我同意它可以简化,但为了清楚起见,我保留原样。
【解决方案3】:

您可以添加一个扩展 FirstEqual:

public static IEnumerable<T> FirstEqual<T>(this IEnumerable<T> source)
{

      var e = source.GetEnumerator();
      if (e.MoveNext())
      {

          T first = e.Current;
          yield return first;
          while (e.MoveNext())
          {

             if (e.Current.Equals(first))
                yield return first;
              else 
                 break;
          }

      }
}

比你打电话的时候

scoreArray.OrderBy(x =&gt; Math.Abs((long)x - realScore)).FirstEqual()

这将返回一个相等数字的集合。

我们还可以返回第一个数字及其计数的元组。

【讨论】:

  • 刚刚抛出索引异常。就像我在编辑问题的底部得到的那样。
猜你喜欢
  • 2017-05-12
  • 1970-01-01
  • 2021-12-08
  • 2011-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多