【问题标题】:Remove the same values when comparing multiple lists比较多个列表时删除相同的值
【发布时间】:2020-01-18 05:37:16
【问题描述】:

我有 3 个人住在 3 个房子里。

  • 人 A (Joe) 住在 1 号房子里。
  • B 人(简)住在 2 号房子里。
  • C 人(Max)住在 3 号房子里。

我有一个按钮,我可以用它为某些人分配任务。它成为一种用户管理。 例如A 有权限进入 C 家。

我希望能够只显示尚未分配的房屋。

图示如下:

  • Joe 是房子 A 的所有者和房子 B 的看守人。

如果我现在想为他分配一个新角色(C 房的看守人),我希望只有 C 房(唯一未分配的房屋)显示在下拉列表中。

问题:目前显示所有房屋。

代码结构:

我可以创建一个新的人或编辑一个现有的人。我有一个用于角色分配的枚举类:

public enum RoleType
{
    [Display(Name = "Owner")]
    Owner = 0,

    [Display(Name = "Janitor")]
    Janitor = 1
}

我还有一个角色定义模型:

public class RoleDefinitionModel
{
    private RoleType? _role;
    private House _selectedHouse;
    
    public RoleDefinitionModel(IList<House> availableHouse, RoleType? selectedRole, House selectedHouse)
    {
        AvailableHouses = availableHouse;
        _role = selectedRole;
        _selectedHouse = selectedHouse;
        StartChangeTracking();
    }
    
    public virtual RoleType? SelectedRole
    {
        get { return _role; }
        set
        {
            if (_role == value)
                return;
            _role = value;
            NotifyChanges();
        }
    }
    
    public virtual House SelectedHouse
    {
        get { return _selectedHouse; }

        set
        {
            if (_selectedHouse == value)
                return;
            _selectedHouse = value;
            NotifyChanges();
        }
    }
    
    public virtual IList<House> AvailableHouses { get; }

    public virtual IList<RoleType> AvailableRoles { get; } = Enum<RoleType>.GetValues().ToList();
}

我已经有一个添加和删除方法,它也可以工作。只有一个问题:当我点击按钮时,我得到了我想要的下拉菜单。但我可以选择所有房屋。我只想查看我还没有没有被分配角色的房子。

public virtual void AddRoleDefinition()
{
    var roleDefinition = new RoleDefinitionModel(House, null, null);
    _roleDefinitions.Add(roleDefinition);
    this.SubscribeChanged(roleDefinition);
}

哪种检查方法最有效:

  • Where()Any() 来自 System.Linq:

_roleDefinitions.Where(....Any());

  • Contains()

  • Remove() 在 foreach 循环中?

for (var i = selectedHouse.Count - 1; i >= 0; --i)
{
    if (availableHouses.Contains(selectedHouse[i].Uid))
    {
        availableHouses.Remove(selectedHouse[i]);
    }
}

foreach (var selectedhouse in availableHouses)
{
    ...
}

但是,我认为这种方法是错误的,我的查询在这里是错误的。我该如何解决这个问题?

【问题讨论】:

    标签: c# list dropdown


    【解决方案1】:

    你能不能给你的 House 对象添加一个属性,例如:

    public House()
    {
       ...
       public bool HasBeenAssigned
       {
         get;
         set;
       }
    }
    

    然后使用 LINQ 以仅选择那些尚未分配的 House 对象

    public List<House> AvailableHouses 
    { 
      return ListOFHouses.Where(house => !house.HasBeenAssigned).Select(item => item).toList();
    }
    

    关于我建议采用哪种方法 - 根据我在回答 LINQ 中的用法。

    foreach 循环没有任何问题 - 但是正如您所见,LINQ 语句更具可读性、可维护性、优雅性,并且它的显示意图。

    在这种情况下,使用 Where 子句会更合适——我们正在查看房子列表where,HasBeenAssigned 的值是 false。这将返回我们选择的可枚举列表,并将其转换为列表。

    我们不感兴趣是否有 any 这意味着布尔结果。事实上,Any 子句将返回一个布尔列表。

    【讨论】:

    • 嗨@AlexLeo,从您对事实的描述和解释来看,这似乎是最好的解决方案,尤其是作为一个简单的实现。我已将更改合并到我的代码中,它似乎运行良好。非常感谢!
    • 嗨@41 72 6c,我很高兴它有帮助。
    【解决方案2】:

    假设您有两个房屋清单。
    第一个,您系统中所有房屋的列表:List&lt;House&gt; allHouses
    第二个,已分配给某人的房屋清单:List&lt;House&gt; assignedHouses
    然后,可分配的房屋:

    var allHouses = new[]
    {
        new House { Uid = 1, Name = "House 1" },
        new House { Uid = 2, Name = "House 2" },
        new House { Uid = 3, Name = "House 3" },
    };
    var assignedHouses = new[] { allHouses[0] };
    
    var availableHouses = allHouses.Where(house => assignedHouses.All(assigned => 
        assigned.Uid != house.Uid)).ToList();
    Console.WriteLine($"Available houses: {string.Join(",", availableHouses.Select(i => i.Name))}");
    Console.Read();
    

    因此,回答您的问题,“Where(...All)”似乎是获得尚未分配的房屋的最清晰方法。

    【讨论】:

      【解决方案3】:

      尝试一个例外查询: var availableHouses = allHouses.ToList().Except(assignedHouses).ToList(); 因此您将获得所有可用的房屋除了已分配的房屋。

      【讨论】:

        【解决方案4】:

        我想说,在这种情况下,将 LINQ 与当前模型/变量一起使用是错误的工作工具。不要忘记,即使您使用.ToList() 保存了未分配房屋查询的结果,下次有人在房屋中添加或删除人员时,您也需要执行整个 再次查询。这意味着同时浏览两个可能很长的列表,并检查一个的元素是否存在于另一个中。这非常低效,尤其是在列表没有排序的情况下。

        IMO 一个好的解决方案可能是维护 3 个列表:allHousesassignedHousesfreeHouses。每当您分配房子时,您都会从freeHouses 中删除对它的引用并将其添加到assignedHouses。这样,您总是可以通过简单地迭代单个列表来访问所需类型的房屋。

        另一种可能性是修改House 的模型,添加对拥有该房屋的人的引用。那么您可能只使用allHouses 的列表,但您将通过以下查询获得所有免费房屋:allHouses.Where(house =&gt; house.Owner == null)。或者不是单个Owner,它可能是与此House 有某种关系的所有人的集合,但你明白了。

        【讨论】:

        • 嗨@DanielCrha,非常感谢您的努力和回答,这也进一步帮助了我。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-05-17
        • 1970-01-01
        • 2016-09-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多