这在LINQ中是否可行?

时间:2015-10-16 04:19:50

标签: c# linq

是否可以仅返回与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查询。

5 个答案:

答案 0 :(得分:1)

您可以先将kList分组,然后将SequenceEqualtid一起使用,这是一个演示

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。

之后,我们需要选择所有tidExcept 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

返回元素004public 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中对数据进行分组,并使用kidTableid列表创建新列表。然后通过将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的那些组的密钥。