如果键匹配,如何从元组中提取一个值
Posted
技术标签:
【中文标题】如果键匹配,如何从元组中提取一个值【英文标题】:How to pull one tvalue from Tuple if key matches 【发布时间】:2021-01-30 06:22:36 【问题描述】:在我的程序中,我加入了两个 IEnumerables 并将它们转换为字典,如下所示:
//list1 is a list of all contracts, list2 is a list of special contracts
var list1 = //List of objects
Var list2 = //List of objects
var combined = List1.Join(list2, c=> s.contractNumber, dto => dto.contract, (s, dto) => dto)
.ToDictonary( x => x.Contract, y => y.Date);
var final = list1.Select(contractNumber =>
var number = contract.ContractNumber;
contract.Date = combined.ContainsKey(number) ? combined[number] : string.Empty;
简短的版本是这样的:我们使用 list1 来填充我们在前端显示的表格,但业务请求的更改需要显示来自单独 API 调用的信息。 List1 没有包含日期字段,但 list2 包含。所以我们将属性添加到list1中,然后使用字典根据键值对填充属性。
他们再次请求在前端显示来自 list2 的另一个字段,所以我想使用这样的元组:
.ToDictionary(x=>x.Contract, y => Tuple.Create(y.Date, y.Type));
但我在这里更新代码时遇到了困难:
contract.Date = combined.ContainsKey(number) ? combined[number] : string.Empty; //It breaks due to converting tuple<string, string> to string
使用基于键的元组中的值之一填充字段的最佳方法是什么?
【问题讨论】:
尝试 null 而不是 string.Empty 问题是当条件为真时,组合的[数字]部分。 IT 想要提取与该键关联的值,但现在有两个值,所以它很困惑。我需要它只使用 Value1 使用:combined.Item2 combined[number].Item2 有效。谢谢! 我不明白你的代码。例如,var final = list1.Select(contractNumber =>
行声明了一个带有参数 contractNumber
的 lambda,该参数在任何地方都没有使用。之后出现一个变量contract
,它没有在任何地方声明。另外我不确定属性s.contractNumber
和contract.ContractNumber
是否不同,或者相同的属性是否存在转录错误(以c
而不是C
开头)。
【参考方案1】:
在我看来,list1 是一系列相似的项目,我们称它们为Contracts
。每个Contract
都有一个属性ContractNumber
。
List2 也是一系列相似的项目。不知道里面有什么,但我们称他们为ContractDates
。每个ContractDate
都有属性Contract
和一个Date
。
哦,我差点忘了:ContractDate.Contract
是 ContractDate 所属的 Contract 的 ContractNumber。所以如果 ContractDate.Contract 等于 14,那么这个 ContractDate 就属于编号为 14 的 Contract。
最后:关系是一对零或一:每个 Contract 都有零个或一个 ContractDate,每个 ContractDate 恰好属于一个 Contract,即外键 Contract 所指的 Contract。
所以可能有没有 ContractDate 的合同
您似乎想要所有合同的(几个属性),每个合同都有其ContractDate
的日期。如果合同没有 ContractDate,那么您希望使用 Date 的默认值(在您的情况下为 String.Empty)
您是对的,每当您使用项目表时,其中每个项目都有来自另一个表的零个或多个项目,并且您想要组合这两个表,您使用某种连接。
如果您想要项目,每个项目都有其唯一的其他项目,请使用加入。如果您希望每个项目都有零个或多个其他项目,请使用 GroupJoin。
所以GroupJoin在以下情况下:
有零个或多个学生的学校 有零个或多个订单的客户 具有零个或多个 ContractDates 的合同(在您的情况下:零个或一个)如果你想反过来使用 Join:
他们就读的唯一一所学校的学生 下订单的客户的订单 外键引用的合同的合同日期。你有你的问题,因为你走错了方向:你应该使用 one of the overloads of GroupJoin 而不是 Join。
在您的情况下,最好使用带有参数 resultSelector 的重载:对于每个具有零个或多个 ContractDates(在您的情况下:零或一)的合约,创建一个新对象:
IEnumerable<Contract> contracts = ...
IEnumerable<ContractDate> contractDates = ...
var contractsWithTDates = contracts.GroupJoin(contractDates,
contract => contract.ContractNumber, // from every contract take the number
contractDate => contractDate.Contract, // from every contractDate take the foreign key
// parameter resultSelector: for every Contract, with its zero or more ContractDates
// make one new object:
(contract, contractDatesOfThisContract) => new ...);
现在你想要什么作为结果对象:
我想要合约的几个参数
我想要唯一的 ContractDate 的日期,如果没有 ContractDate,则为 String.Empty
常量字符串 defaultContractDate = String.Empty; var contractsWithTDates =contracts.GroupJoin(contractDates, ...
(contract, contractDatesOfThisContract) => new
// Select the zero or more properties of the contract that you want:
ContractNumber = contract.ContractNumber,
CustomerId = contract.CustomerId,
...
// Select the properties of the contract dates of this contract that you want
// if there is one: use the date
// if there is none: use the defaultContractDate
// if there is more than one, which you don't expect, use the first contractDate
Date = contractDatesOfThisContract
.Select(contractDate => contractDate.Date)
.FirstOrDefault() ?? defaultContractDate,
);
简而言之:对于 contractDatesOfThisContract 中的每个 Date(您最多期望其中一个),选择属性 Date。从生成的日期序列中,取第一个,或者如果没有第一个,则返回“默认”,在这种情况下为空。
操作员 ?? (null-coalescing operator):如果 FirstOrDefault 的结果非 null,则使用该值,如果为 null,则使用 defaultContractDate。
【讨论】:
感谢您的详细回复。你对情况有大致的了解。然而,问题不在于合同日期。这是相当容易提供的初始请求。当他们回来说哦,我们还需要显示另一个属性时,问题就来了。 cmets 中为我的问题提供了快速解决方案——使用元组工作我只是错过了 .Item1/.item2 语法以上是关于如果键匹配,如何从元组中提取一个值的主要内容,如果未能解决你的问题,请参考以下文章