这与我上一期的问题相似;但是从不同的角度来看。 See if item exists once in Enumerable (Linq)
给出以下一组项目,以及包含它们的列表......
Item 1
Item 2
Item 3
Item 4
Item 5
class Item
{
string Name { get; set; }
}
List<Item> available = new List<Item>()
{
Item 1
Item 1
Item 2
Item 3
Item 5
}
List<Item> selected = new List<Item>()
{
Item 1
Item 2
Item 3
}
我需要创建一个包含“available”的第三个List,除了“selected”中的内容。 但是,“第1项”处于“可用”状态两次,但仅在“已选择”一次。由于它们是同一项目的实例,因此我无法找出适当的逻辑来适应这一点。
最终的数组应该看起来像......
List<Item> selectable = new List<Item>()
{
Item 1
Item5
}
答案 0 :(得分:2)
这是一种有点棘手的方法,但它完成了工作。我借用了Python中的“Decorate-Sort-Undecorate”习语,它通过将临时排序键与数组相关联来进行排序,并结合.NET中的匿名类型具有默认EqualityComparer的有趣且有用的事实,该EqualityComparer基于他们的领域的价值观。
步骤1:按名称对每个列表中的元素进行分组,然后将索引与每个组中的每个项相关联,并将这些组展平回常规列表:
var indexedAvailable = available.GroupBy(i => i.Name)
.SelectMany(g => g.Select((itm, idx) => new
{ Name = itm.Name, Index = idx }));
var indexedSelected = selected.GroupBy(i => i.Name)
.SelectMany(g => g.Select((itm, idx) => new
{ Name = itm.Name, Index = idx }));
这会将列表转换为:
indexedAvailable indexedSelected
Name = Item 1, Index = 0 Name = Item 1, Index = 0
Name = Item 1, Index = 1 Name = Item 2, Index = 0
Name = Item 2, Index = 0 Name = Item 3, Index = 0
Name = Item 3, Index = 0
Name = Item 5, Index = 0
现在您可以看到,在索引列表中,available
中任何名称的每个编号出现次数仅与等效编号的出现的匹配项匹配selected
中的同名。因此,您可以使用简单的Except
删除不在indexedAvailable
中的indexedSelected
中的任何内容,然后通过将匿名类型的索引对象转回{{1}来“删除” }第
Item
证明:
var selectable = indexedAvailable.Except(indexedSelected)
.Select(i => new Item() { Name = i.Name });
请注意,即使foreach (var item in selectable)
Console.WriteLine(item.Name);
//prints out:
//Item 1
//Item 5
包含不在selected
中的名称,这也可以使用,例如如果第二个列表在您的上一个问题中有available
。
答案 1 :(得分:1)
可能有LINQ方法来完成此任务。你当然可以获得5项,因为它是独一无二的,但第二项1可能很难。但是,您可以始终以旧式方式执行此操作并自行创建新列表。考虑这个例子:
class Item
{
public Item(string name) { Name = name; }
public string Name { get; set; }
}
...
List<Item> available = new List<Item>()
{
new Item("1"), new Item("1"), new Item("2"), new Item("3"), new Item("5")
};
List<Item> selected = new List<Item>()
{
new Item("1"),new Item("2"), new Item("3")
};
List<Item> stillAvailable = new List<Item>();
List<Item> stillSelected = new List<Item>(selected);
foreach (Item item in available)
{
Item temp = stillSelected.Find(i => i.Name == item.Name);
if (temp == null)
stillAvailable.Add(item);
else
stillSelected.Remove(temp);
}
您可以为仍然可用的项目创建一个列表,该列表最初为空。您为仍然选中的项目创建一个列表,其中包含所有选定的项目。然后,您只需遍历可用项并搜索stillSelected列表。如果找到该项,则将其从stillSelected列表中删除。如果没有,则将其添加到stillAvailable列表中。在循环结束时,stillAvailable将包含单个项目1和项目5.
答案 2 :(得分:1)
var comp = new MyEqualityComparer();
selectable = available.Distinct(comp).Except(selected, comp);