gpt4 book ai didi

c# - 对列表求和,但仅针对某个点之后的值

转载 作者:行者123 更新时间:2023-12-04 11:47:10 25 4
gpt4 key购买 nike

我正在写一个网页来记录纸牌游戏的分数。到目前为止让球员得分很容易,但有一个转折点。在任何回合中,玩家得分可以在回合开始时重置为零。我不想更改任何前几轮的得分,所以我只想在(包括)重置后获得轮次的总和。玩家可能会在一场比赛中多次重置他们的分数,或者根本不重置。
我可以通过一个多阶段的过程来获得正确的分数,即找到最后一次(如果有的话)分数重置,然后对所有手牌(或所有手牌没有重置)求和 - 请参阅 PlayerGame.GetPlayerScore。
我仍然试图了解使用 LINQ 做事情的更复杂的方法,我想知道是否有办法使用单个 LINQ 语句来做到这一点?
最小代码:

class Program
{
static void Main(string[] args)
{
PlayerGame playerGame = new PlayerGame();

playerGame.PlayerHands = new List<PlayerHand>
{
new PlayerHand { Round = 1, Score = 10 },
new PlayerHand { Round = 2, Score = 20 },
new PlayerHand { Round = 3, Score = 30 },
new PlayerHand { Round = 4, Score = 40, Reset = true },
new PlayerHand { Round = 5, Score = 50 },
new PlayerHand { Round = 6, Score = 60 }
};

Console.WriteLine($"Players score was {playerGame.GetPlayerScore()}");
Console.ReadLine();
}
}

class PlayerHand
{
public int Round { get; set; }
public int Score { get; set; }
public bool Reset { get; set; } = false;
}

class PlayerGame
{
public List<PlayerHand> PlayerHands { get; set; }

public PlayerGame()
{
PlayerHands = new List<PlayerHand> { };
}

public int GetPlayerScore()
{
// Can all this be simplified to a single LINQ statement?
var ResetIndex = PlayerHands.OrderBy(t => t.Round).LastOrDefault(t => t.Reset == true);

if (ResetIndex != null)
{
return PlayerHands.Where(t => t.Round >= ResetIndex.Round).Sum(t => t.Score);
}
else
{
return PlayerHands.Sum(t => t.Score);
}
}
}
https://dotnetfiddle.net/s5rSqJ
如上所示,玩家得分应为 150。即分数在第 4 轮开始时重置,因此总分是第 4、5 和 6 轮的总和。

最佳答案

总结几点,

  • 回合数是有限的(否则是一场非常漫长的比赛!)。当我们在下面谈论逆转时,这一观察很重要。
  • 回合已经按升序排序(根据评论),因此实际回合数无关紧要
  • 如果我们向后求和,我们就不必扫描整个列表

  • 所以,我们可以想出一个实现,即 O(1) 空间(就地,无分配)和 O(n) 时间(线性,小于重置时列表的大小)。
    使用 MoreLinq
    var score = hands.ReverseInPlace().TakeUntil(x => x.Reset).Sum(x => x.Score);
    哪里 ReverseInPlace()以相反的顺序原地迭代,并且 MoreEnumerable.TakeUntil()占用并包括具有 Reset 真值的回合或序列结束。 ReverseInPlace将是一种扩展方法(如果需要,您可以概括为 IEnumerable<>)。
    public static class ListExtensions
    {
    public static IEnumerable<T> ReverseInPlace<T>(this IList<T> source)
    {
    // add guard checks here, then do...
    for (int i=source.Length-1; i != -1; --i)
    yield return source[i];
    }
    }
    不使用 MoreLinq
    您可以创建一个 TakeInReverseUntil :
    public static IEnumerable<T> TakeInReverseUntil<T>(this IList<T> source, Func<T, bool> predicate)
    {
    // add guard checks here, then do...
    for (int i=source.Length-1; i != -1; --i)
    {
    yield return source[i];
    if (predicate(source[i]) yield break;
    }
    }
    给你简化的电话
    var score = hands.TakeInReverseUntil(x => x.Reset).Sum(x => x.Score);
    注意: Enumerable.Reverse()分配一个缓冲区,所以 O(n) 空间,这就是为什么我推出自己的 ReverseInPlace而不是这个答案。

    关于c# - 对列表求和,但仅针对某个点之后的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67676964/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com