使用 linq c# 根据多个值进行左连接和计数
Left join and count based on multiple values using linq c#
我有 2 个列表。列表 A 包含此值,
status | level
-----------------
open | low
open | medium
open | high
closed | low
closed | medium
closed | high
列表 B 包含此值,
task | status | level
------------------------
A | open | low
B | open | medium
C | closed | high
D | closed | low
E | open | low
我想做left join(列表A中的所有值必须在新列表中),并统计与状态相关的任务数。我也想要级别值,因为稍后将在我的代码中使用它。预期输出:
status | level | count
-------------------------
open | low | 2
open | medium | 1
open | high | 0
closed | low | 1
closed | medium | 0
closed | high | 1
我知道这里有很多答案提供了编码的方法,但我仍然卡住了,因为我的代码不起作用,它似乎没有按方法进行分组,因为当我计数时,值显示的是所有状态。
var joined3 = (from id1 in joined
join id2 in tr
on new { lev = id1.Key.ToString(), stat = id1.Value.ToString() } equals new { lev = id2.Level.ToString(), stat = id2.Status.ToString() } into grouped
from id2 in grouped.DefaultIfEmpty()
group id2 by new {level = id1.Key, status = id1.Value } into grouped
select new
{
level = grouped.Key.level,
status = grouped.Key.status,
count = grouped.Count()
}).ToList();
var list1 = new List<Type1>
{
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.Low},
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.Medium},
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.High},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.Low},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.Medium},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.High}
};
var list2 = new List<Type2>
{
new Type2() {TaskDescription = "A", Status = StatusEnum.Open, Level = LevelEnum.Low},
new Type2() {TaskDescription = "B", Status = StatusEnum.Open, Level = LevelEnum.Medium},
new Type2() {TaskDescription = "C", Status = StatusEnum.Closed, Level = LevelEnum.High},
new Type2() {TaskDescription = "D", Status = StatusEnum.Closed, Level = LevelEnum.Low},
new Type2() {TaskDescription = "E", Status = StatusEnum.Open, Level = LevelEnum.Low}
};
var list3 = new List<Type3>();
foreach (var t in list1)
{
list3.Add(new Type3()
{Level = t.Level, Status = t.Status, Count = list2.Count(x => x.Level == t.Level && x.Status == t.Status)});
}
foreach (var t in list3)
{
Console.WriteLine($"{t.Status}/{t.Level}/{t.Count}");
}
class Type1
{
public StatusEnum Status { get; set; }
public LevelEnum Level { get; set; }
}
class Type2 : Type1
{
public string TaskDescription { get; set; }
}
class Type3 : Type2
{
public int Count { get; set; }
}
public enum StatusEnum
{
Open,
Closed
}
public enum LevelEnum
{
Low,
Medium,
High
}
问题在于,由于 DefaultIfEmpty()
的 left-join 语义,您总是至少有一行。所以你需要给 Count()
添加一个谓词
var joined3 = (
from id1 in joined
join id2 in tr
on new { lev = id1.Key, stat = id1.Value } equals new { lev = id2.Level, stat = id2.Status } into grouped
from id2 in grouped.DefaultIfEmpty()
group id2 by new {level = id1.Key, status = id1.Value } into grouped
select new
{
level = grouped.Key.level,
status = grouped.Key.status,
count = grouped.Count(id2 => id2.Key != null)
}).ToList();
或者,更简单的方法是:不分组,而是使用其他列表的相关计数
var joined3 = (
from id1 in joined
select new
{
level = id1.level,
status = id1.status,
count = tr.Count(id2 => id2.Key == id1.Key && id2.Value == id1.Value)
}).ToList();
I see no reason to use ToString
here, and it is likely to impact performance. Key
and Value
should be the same type on each list/table respectively.
我有 2 个列表。列表 A 包含此值,
status | level
-----------------
open | low
open | medium
open | high
closed | low
closed | medium
closed | high
列表 B 包含此值,
task | status | level
------------------------
A | open | low
B | open | medium
C | closed | high
D | closed | low
E | open | low
我想做left join(列表A中的所有值必须在新列表中),并统计与状态相关的任务数。我也想要级别值,因为稍后将在我的代码中使用它。预期输出:
status | level | count
-------------------------
open | low | 2
open | medium | 1
open | high | 0
closed | low | 1
closed | medium | 0
closed | high | 1
我知道这里有很多答案提供了编码的方法,但我仍然卡住了,因为我的代码不起作用,它似乎没有按方法进行分组,因为当我计数时,值显示的是所有状态。
var joined3 = (from id1 in joined
join id2 in tr
on new { lev = id1.Key.ToString(), stat = id1.Value.ToString() } equals new { lev = id2.Level.ToString(), stat = id2.Status.ToString() } into grouped
from id2 in grouped.DefaultIfEmpty()
group id2 by new {level = id1.Key, status = id1.Value } into grouped
select new
{
level = grouped.Key.level,
status = grouped.Key.status,
count = grouped.Count()
}).ToList();
var list1 = new List<Type1>
{
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.Low},
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.Medium},
new Type1() {Status = StatusEnum.Open, Level = LevelEnum.High},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.Low},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.Medium},
new Type1() {Status = StatusEnum.Closed, Level = LevelEnum.High}
};
var list2 = new List<Type2>
{
new Type2() {TaskDescription = "A", Status = StatusEnum.Open, Level = LevelEnum.Low},
new Type2() {TaskDescription = "B", Status = StatusEnum.Open, Level = LevelEnum.Medium},
new Type2() {TaskDescription = "C", Status = StatusEnum.Closed, Level = LevelEnum.High},
new Type2() {TaskDescription = "D", Status = StatusEnum.Closed, Level = LevelEnum.Low},
new Type2() {TaskDescription = "E", Status = StatusEnum.Open, Level = LevelEnum.Low}
};
var list3 = new List<Type3>();
foreach (var t in list1)
{
list3.Add(new Type3()
{Level = t.Level, Status = t.Status, Count = list2.Count(x => x.Level == t.Level && x.Status == t.Status)});
}
foreach (var t in list3)
{
Console.WriteLine($"{t.Status}/{t.Level}/{t.Count}");
}
class Type1
{
public StatusEnum Status { get; set; }
public LevelEnum Level { get; set; }
}
class Type2 : Type1
{
public string TaskDescription { get; set; }
}
class Type3 : Type2
{
public int Count { get; set; }
}
public enum StatusEnum
{
Open,
Closed
}
public enum LevelEnum
{
Low,
Medium,
High
}
问题在于,由于 DefaultIfEmpty()
的 left-join 语义,您总是至少有一行。所以你需要给 Count()
var joined3 = (
from id1 in joined
join id2 in tr
on new { lev = id1.Key, stat = id1.Value } equals new { lev = id2.Level, stat = id2.Status } into grouped
from id2 in grouped.DefaultIfEmpty()
group id2 by new {level = id1.Key, status = id1.Value } into grouped
select new
{
level = grouped.Key.level,
status = grouped.Key.status,
count = grouped.Count(id2 => id2.Key != null)
}).ToList();
或者,更简单的方法是:不分组,而是使用其他列表的相关计数
var joined3 = (
from id1 in joined
select new
{
level = id1.level,
status = id1.status,
count = tr.Count(id2 => id2.Key == id1.Key && id2.Value == id1.Value)
}).ToList();
I see no reason to use
ToString
here, and it is likely to impact performance.Key
andValue
should be the same type on each list/table respectively.