这在LINQ中是可能的吗?
本文关键字:LINQ 这在 | 更新日期: 2023-09-27 18:18:00
是否可以只返回与LINQ
中所有列表值匹配的值?
我有一个表klist
,其中有两列可用:
Kid - Tableid
001 1
001 2
002 1
003 3
004 1
004 2
和我有一个包含tid
值的列表:
List<int> tid = new List<int>();
tid.Add(1);
tid.Add(2);
现在tid
列表有1和2的值。
所以我的问题是,从klist
表,我只会得到那些kid
包含所有的tid
列表值,并与表id比较。
之后的预期结果是
kid - 001
kid - 004
我试了下面的查询:
var lb = Klist.Where(t => tid .Contains(t.Tableid)).Select(k => k.Kid).Distinct().ToList();
返回所有匹配子,即使是单个匹配,也会给出结果,但我只想要那些匹配所有表id与tid list的子。我查询的结果是
kid - 001
kid - 002
kid - 003
kid - 004
请建议LINQ
查询。
为了实现你想要的,你首先需要通过Kid
:
Group
:
Klist.GroupBy(k => k.Kid)
结果是一个不同的Kid
s及其对应的Tableid
s的列表。
之后,我们需要选择所有Tableid
s与tid
s相同的组。这可以通过使用Except
从两个列表中删除相同的元素来实现。然后检查是否没有剩余元素(即两个集合相等)。
.Where(g => tid.Except(g.Select(s => s.Tableid)).Count() == 0)
最后,获取其余组的Kid
,它作为Key
存储在组中:
.Select(g => g.Key);
如果我们将所有内容组合在一起,我们得到以下LINQ查询:
var lb = Klist.GroupBy(k => k.Kid).Where(g => tid.Except(g.Select(s => s.Tableid)).Count() == 0).Select(g => g.Key);
返回元素001
和004
您可以先将kList
分组,然后将SequenceEqual
与tid
一起使用,下面是一个示例
List<KeyValuePair<string, int>> kList = new List<KeyValuePair<string, int>>()
{
new KeyValuePair<string, int>("001",1),
new KeyValuePair<string, int>("001",2),
new KeyValuePair<string, int>("002",1),
new KeyValuePair<string, int>("003",3),
new KeyValuePair<string, int>("004",1),
new KeyValuePair<string, int>("004",2)
};
List<int> tid = new List<int>() { 1, 2 };
var query = kList.GroupBy(i => i.Key)
.Where(g => g.Select(j => j.Value).Distinct().OrderBy(i => i).SequenceEqual(tid))
.SelectMany(g => g.Select(x => x.Key)).Distinct();
Console.WriteLine(string.Join(",", query));
和SequenceEqual
可能有一些问题,如果你想要contains
所有的tid
,而不是Equal
,那么你可以使用Intersect
来代替SequenceEqual
,代码是这样的
List<KeyValuePair<string, int>> kList = new List<KeyValuePair<string, int>>()
{
new KeyValuePair<string, int>("001",1),
new KeyValuePair<string, int>("001",2),
new KeyValuePair<string, int>("002",1),
new KeyValuePair<string, int>("001",3),//special one
new KeyValuePair<string, int>("003",3),
new KeyValuePair<string, int>("004",1),
new KeyValuePair<string, int>("004",2)
};
List<int> tid = new List<int>() { 1, 2 };
var query = kList.GroupBy(i => i.Key)
.Where(g => g.Select(j => j.Value).Distinct().Intersect(tid).Count()==tid.Count)
.SelectMany(g => g.Select(x => x.Key)).Distinct();
Console.WriteLine(string.Join(",", query));
效果很好:
var kList = new []
{
new { Kid = "001", Tableid = 1 },
new { Kid = "001", Tableid = 2 },
new { Kid = "002", Tableid = 1 },
new { Kid = "003", Tableid = 3 },
new { Kid = "004", Tableid = 1 },
new { Kid = "004", Tableid = 2 },
};
var tid = new List<int>() { 1, 2, };
var lookup = kList.ToLookup(k => k.Tableid, k => k.Kid);
这产生:
1 => "001", "002", "004"
2 => "001", "004"
3 => "003"
var result = tid.Select(t => lookup[t]).Aggregate((ts0, ts1) => ts0.Intersect(ts1));
tid.Select(...)
产生{ { "001", "002", "004" }, { "001", "004" } }
,然后Aggregate
对这两个执行相交。
结果是:
001
004
另一种方法:
var list = kList.GroupBy(x => x.Kid)
.Select(group => new
{
Kid = group.FirstOrDefault().Kid,
gtid = group.Select(groupItem => groupItem.Tableid).ToList()
})
.Where(group => !group.gtid.Except(tid).Any()
&& !tid.Except(group.gtid).Any())
.Select(group => group.Kid);
基本上像其他解决方案一样,您将kList
中的数据分组,并使用kid
和Tableid
列表创建一个新列表。然后通过比较Tableid
列表和tid
列表来过滤新列表(确保一个列表中没有不在另一个列表中的列表项,反之亦然)。然后,选择kid
值。
有很多答案是Except(Func<T, bool>).Any()
或Except(Func<T, bool>).Count() == 0
,但这两个组合似乎都应该是All(Func<T, bool>)
。
根据你的问题,你说你只想要kid
值,当它存在于All
行kid
值。这就是我要做的。
var lb = klist.GroupBy(lst => lst.Kid)
.Where(t => tid.All(td => t.Select(x => x.TableId).Contains(td)))
.Select(grp => grp.Key);
将表分组为包含Kid
的集合。然后,它过滤掉不存在all
tid值的行。然后为这些组选择键,即Kid
。