Linq - 根据 "weight" 和 "order" 从列表中获取项目

Linq - Get items from the list based on "weight" and "order"

我正在尝试创建一个 class 来计算用户配置文件的 完整性 并且我正在尝试按顺序执行后续步骤(评估程序)让用户达到下一个完整性水平。

public class Evaluator
{
    public Evaluator(string name, int value, Func<CompletionStatus, bool> rule)
    {
        Name = name;
        Value = value;
        Action = rule;
    }

    public int Value { get; private set; }
    public Func<Completion, bool> Rule { get; private set; }
    public bool IsCompleted { get;set; }

    public int Run(CompletionStatus status)
    {
         IsCompleted = Rule(status);
         return IsCompleted ? Value : 0;        
    }
}

class CompletionManager
{
     public List<Evaluator> Evaluators { get;set; }

     public CompletionManager() {

        Evaluators = new List<Evaluator>() {
        new Evaluator("Email", 10, status => !String.IsNullOrWhiteSpace(status.Email)),
        new Evaluator("DOB", 10, status => status.DateOfBirth.HasValue),
        new Evaluator("Mobile", 20, status => !String.IsNullOrWhiteSpace(status.Mobile)),
        new Evaluator("Address", 20, status => !String.IsNullOrWhiteSpace( status.Address)),
        new Evaluator("Profession", 40, status => status.HasProfession),

    };
}

用法

  Main() {

   var status = new CompletionStatus
            {
                Email = "dummy@gmail.com",
                DateOfBirth = null,
                Mobile = "",
                Address = "",
                HasProfession = false,
            };

    CompletionManager cm = new CompletionManager();

     var profileCompletion = (byte) cm.Evaluators
            .Select(evaluator => evaluator.Run(status))
            .Sum();

     profileCompletion.Dump(); // result= 10% complete

     var nextEvaluators = cm.EvaluatorsToTheNextLevel(profileCompletion); // get the next 40%

 }

问题:在此示例中 - 我如何获取对应于用户必须完成的下一个 40% 的 Evaluator 列表,以便配置文件完成为 >= 50%;

在上面的例子中,我想得到 Evaluator("DOB")Evaluator("Mobile")Evaluator("Address")

class CompletionManager {
....
 public List<Evaluator> EvaluatorsToTheNextLevel(int completionStatus) {

    // assuming completionStatus = 10%, then we have to get the next 40% worth of evaluators
       var percentBeforeNxtLevel = 50 - completionStatus;
       return Evaluators.Where(e => e.IsCompleted == false && ???);
   }
}

注意:还考虑了评估者的顺序,因此如果我们要获得下一个 40%,我们不需要 Evaluator("Profession"),因为它位于堆栈的底部

还有:这应该是灵活的;如果我这样做

var status = new CompletionStatus
            {
                Email = "",
                DateOfBirth = null,
                Mobile = "091920",
                Address = "",
                HasProfession = false,
            };

那么我们应该得到 Evaluator("Email"), Evaluator("DOB"), Evaluator("Address")

你可以这样做:

public List<Evaluator> EvaluatorsToTheNextLevel(int completionStatus) {

    // assuming completionStatus = 10%, then we have to get the next 40% worth of evaluators
       var percentBeforeNxtLevel = 50 - completionStatus;
       var tmp = 0;
       return Evaluators
          .Where(e => e.IsCompleted == false)
          .TakeWhile(x => {
              tmp +=x.Value;
              return tmp <= percentBeforeNxtLevel;
            })
           .ToList();
   }

当然,这也可以通过简单的 while 循环轻松实现...

下面的行将不起作用

.Select(evaluator => evaluator.Run(status))
​

您正在按照评估者进入列表<>的顺序一次枚举一个评估者。您的函数需要所有求值器才能传递整个列表 'Evaluators'.