比较多个列表时,移除相同的值。

3

我有三个人住在三所房子里。

  • Person A(乔)住在1号房屋。
  • Person B(简)住在2号房屋。
  • Person C(马克斯)住在3号房屋。

我有一个按钮,用它可以为特定的人做任务分配。它变成了一种用户管理。例如:Person A有权限进入C房。

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

说明如下:

  • 乔是A房的所有者和B房的看守。

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

enter image description here

问题:当前所有房屋都被显示。

代码结构:

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

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);
}

哪种方法是最有效的检查方式:

  • System.Linq 中的 Where()Any()

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

  • Contains()

  • 或者在 foreach 循环中使用 Remove()

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

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

然而,我认为这种方法是错误的,我的查询也是错误的。我该如何解决?

4个回答

1
尝试Except查询: var availableHouses = allHouses.ToList().Except(assignedHouses).ToList(); 这样,您将获得所有可用房屋,除了已分配的房屋。

1
我认为在这种情况下,使用当前的模型/变量和LINQ是错误的工具。不要忘记,即使你保存了一个未分配房屋查询的结果,并使用.ToList(),下一次有人添加或从房子中删除一个人,你将需要重新执行整个查询。这意味着同时遍历两个潜在的长列表,并检查一个列表中的元素是否存在于另一个列表中。这相当低效,特别是如果列表没有排序。
在我看来,一个好的解决方案可能是维护三个列表:allHousesassignedHousesfreeHouses。每当你分配一个房子时,你就从freeHouses中移除它的引用,并将其添加到assignedHouses中。这样,你只需迭代一个单一的列表,就可以随时访问所需类型的房屋。
另一种可能性是修改House模型,通过添加对拥有该房屋的人的引用。然后您可能仅使用allHouses列表,但您可以使用以下查询获取所有空闲房屋:allHouses.Where(house => house.Owner == null)。或者,它可以是与此House相关的所有人的集合,而不是单个Owner,但您明白了。

嗨@DanielCrha,非常感谢您的努力和回答,这也进一步帮助了我。 - 41 72 6c

1
假设你有两个房屋列表。
第一个是你系统中所有房屋的列表:List<House> allHouses
第二个是已经分配给某个人的房屋列表:List<House> 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)` 似乎是获取尚未分配的房屋最清晰的方法。

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子句会更合适——我们正在查找房屋列表中值为false的HasBeenAssigned。这将返回一个可枚举的列表,我们选择并将其强制转换为列表。

我们不关心是否有任何一个,这意味着布尔结果。事实上,Any子句将返回一个布尔列表。


嗨@AlexLeo,根据您的描述和事实解释,这似乎是最好的解决方案,特别是作为一种简单的实现方式。我已经将更改合并到我的代码中,看起来运行良好。非常感谢! - 41 72 6c
嗨 @41 72 6c,我很高兴它有帮助。 - Alex Leo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接