Linq to Dictionary<string, List<string>> 与 Null 值
Posted
技术标签:
【中文标题】Linq to Dictionary<string, List<string>> 与 Null 值【英文标题】:Linq to Dictionary<string, List<string>> with Null values 【发布时间】:2019-11-27 10:33:40 【问题描述】:我确实有一个Culture
列表和一个翻译列表:
public class Translation
public string key get; set;
public string value get; set;
public string cultureId get; set;
public async Task<IActionResult> ReactGetResources(string module = "shared")
string[] Languages = "en-US", "fr-FR", "it-IT", "es-ES" ;
List<Translation> Translation = new List<Translation>();
Translation.Add(new Translation key = "hello", value = "Hello", cultureId = "en-US" );
Translation.Add(new Translation key = "hello", value = "Bonjour", cultureId = "fr-FR" );
Translation.Add(new Translation key = "hello", value = "Buongiorno", cultureId = "it-IT" );
Translation.Add(new Translation key = "goodbye", value = "Good Bye", cultureId = "en-US" );
Translation.Add(new Translation key = "goodbye", value = "Au revoir", cultureId = "fr-FR" );
Translation.Add(new Translation key = "goodbye", value = "adiós", cultureId = "es-ES" );
Dictionary<string, List<string>> query = Translation
.OrderBy(o => o.cultureId)
.GroupBy(o => o.key)
.ToDictionary(g => g.Key, g => g.Select(x => x.value).ToList());
return Json(query);
当前代码IActionResult
返回:
"hello": [
"Hello", //en
"Bonjour", //fr
"Buongiorno" //it
],
"goodbye": [
"Good Bye", //en
"Au revoir", //fr
"Adiós", //es
]
但我希望为缺少的翻译添加 Null
值:
"en-US", "fr-FR", "it-IT", "es-ES"
"hello": [
"Hello", //en
"Bonjour", //en
"Buongiorno", //it
null //es
],
"goodbye": [
"Good Bye", //en
"Au revoir", //fr
null, //it
"Adiós" //es
]
可以只用Linq
吗?或者也许我应该在字典里写一个loop
并重新填充山谷?
【问题讨论】:
多个翻译实例可以共享同一个key
?我还以为是PK
,还是和DB
无关?
另一方面,您可以通过使用左连接来连接两个集合来完成您想要的操作。 Google 如何使用 LINQ 进行左连接。
是的,它不是 PK
,要获得特定文化的特定翻译,我在 key
和 cultureId
上搜索
【参考方案1】:
你为什么会期望这一点?您实际上是在告诉它只选择value
。 cultureId
和您的 Languages
数组都没有被提及或使用,那么您为什么还要期望它们以某种方式发挥作用呢?
你需要类似下面的GroupBy
:
.GroupBy(g => g.key, (key, items) => Languages.Select(lang => items.FirstOrDefault(i => i.cultureId == lang)?.value))
【讨论】:
事实上这不是好的答案,hello
和 goodbye
的键没有返回【参考方案2】:
你可以加入你的语言列表,像这样(尚未测试)
Dictionary<string, List<string>> query = Translation
.GroupBy(o => o.key)
.ToDictionary(g => g.Key, g =>
Languages.Select(l => g.FirstOrDefault(x => x.cultureId == l)?.value));
解释:
我们将组映射到语言列表中。对于每种语言,如果与cultureId 匹配的元素在组中,则使用该值,或者改为使用null。
(暂时无法测试,如有错误请见谅)
【讨论】:
编辑了我的答案以包含评论。不需要在 Aleks 的建议中使用 Any 或 Contains 是的,这是一个很好的答案:.ToDictionary(g => g.Key, g => Languages.Select(l => g.FirstOrDefault(x => x.cultureId == l)?.value).ToList());
很高兴它有效。老实说,我更赞成克里斯的回答,因为它在分组中更早地处理了问题。【参考方案3】:
您尝试在 linq 中执行 "left join",这可以使用 Join
和 DefaultIfEmpty
运算符。
只要我知道这只能在声明性语法上进行:
var query = from trans in Translation
group trans by trans.key into transGroup
select new
transGroup.Key,
Values = from langId in Languages
join trans in transGroup on langId equals trans.cultureId
into joint
from trans in joint.DefaultIfEmpty()
select trans?.value
;
var values = query.ToDictionary(x => x.Key, x => x.Values.ToList());
我同意这不是最易读的查询,也许以程序方式维护它会更简单。
【讨论】:
【参考方案4】:使用下面的代码
Dictionary<string, List<string>> query = Translation
.OrderBy(o => o.cultureId)
.GroupBy(o => o.key)
.ToDictionary(g => g.Key, g => Languages.GroupJoin(g.Select(x => x), f => f, s => s.cultureId, (f, s) => s).SelectMany(x => x.DefaultIfEmpty(),(x, y) => y != null? y.value :null).ToList());
并更正最后的翻译
Translation.Add(new Translation key = "goodbye", value = "adiós", cultureId = "es-ES" );
Translation.Add(new Translation key = "goodbye", value = "adiós",cultureId = "es-US" );
【讨论】:
以上是关于Linq to Dictionary<string, List<string>> 与 Null 值的主要内容,如果未能解决你的问题,请参考以下文章
Linq 到 Dictionary<string, string[]>。选择值包含条件字符串的键