是否可以仅返回与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
列表值并与表格ID进行比较的tid
。
此后的预期结果是
kid - 001
kid - 004
我尝试了以下查询:
var lb = Klist.Where(t => tid .Contains(t.Tableid)).Select(k => k.Kid).Distinct().ToList();
但是返回所有匹配的孩子,如果即使是单一匹配,那么他们也会给出结果,但我只想要那些匹配所有表ID和tid列表的人。 我的查询结果是
kid - 001
kid - 002
kid - 003
kid - 004
请为此建议LINQ
查询。
答案 0 :(得分:1)
您可以先将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
的instand 1}},代码就像这样
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));
答案 1 :(得分:1)
为了达到您想要的效果,首先需要Group
Kid
Klist.GroupBy(k => k.Kid)
的价值:
Kid
结果是一个不同的Tableid
列表及其对应的Tableid
s。
之后,我们需要选择所有tid
与Except
s相同的组。这可以通过使用.Where(g => tid.Except(g.Select(s => s.Tableid)).Count() == 0)
从两个列表中删除相同的元素来实现。然后我们检查是否没有剩余元素(即两组相等)。
Kid
最后,获取剩余组的Key
,其中.Select(g => g.Key);
存储在组中:
var lb = Klist.GroupBy(k => k.Kid).Where(g => tid.Except(g.Select(s => s.Tableid)).Count() == 0).Select(g => g.Key);
如果我们将所有内容组合在一起,我们会得到以下LINQ查询:
001
返回元素004
和public static int Count<T>(T[] arr, Predicate<T> condition)
{
int counter = 0;
for (int i = 0; i < arr.Length; i++)
if (condition(arr[i]))
counter++;
return counter;
}
delegate Boolean IsOdds<T>(T x);
delegate bool IsEven(int x);
private void button1_Click(object sender, EventArgs e)
{
IsOdds<int> isOdds = i => i % 2 == 1;//must be <int>, not <T>
IsEven isEven = i => i % 2 == 0;
Action<int> a = x => this.Text = (x*3).ToString();
a(3);
Predicate<int> f = delegate(int x) { return x % 2 == 1; };
Predicate<int> ff = x => x % 2 == 1;
MessageBox.Show("lambada " + Count<int>(new int[] { 1, 2, 3, 4, 5 }, x => x % 2 == 1).ToString());
MessageBox.Show("f " + Count<int>(new int[] { 1, 2, 3, 4, 5 }, f).ToString());
MessageBox.Show("ff " + Count<int>(new int[] { 1, 2, 3, 4, 5 }, ff).ToString());
MessageBox.Show("delegate " + Count<int>(new int[] { 1, 2, 3, 4, 5 }, delegate(int x) { return x % 2 == 1; }).ToString());
MessageBox.Show(Count<int>(new int[] { 1, 2, 3, 4, 5 }, isOdds(int x)).ToString()); //this is wrong
MessageBox.Show(Count<int>(new int[] { 1, 2, 3, 4, 5 }, isEven(int x)).ToString()); //this is wrong
return;
}
答案 2 :(得分:0)
这很有效:
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
答案 3 :(得分:0)
另一种方法可以做到:
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
值。
答案 4 :(得分:0)
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
的那些组的密钥。