如果键匹配,如何从元组中提取一个tvalue

问题描述

在我的程序中,我加入了两个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

使用基于键的元组中的值之一填充字段的最佳方法是什么?

解决方法

在我看来,list1是一系列相似项的序列,我们称它们为Contracts。每个Contract都有一个属性ContractNumber

List2也是一系列相似项。不知道其中有什么,但是我们称它们为ContractDates。每个ContractDate都有属性Contract和一个Date

哦,我几乎忘记了:ContractDate.Contract是ContractDate所属合同的ContractNumber。因此,如果ContractDate.Contract等于14,则此ContractDate属于编号为14的合同。

最后:关系是一对零或一:每个合同都有零个或一个ContractDate,每个ContractDate恰好属于一个合同,即外键合同引用的合同。

所以可能有些合同没有ContractDate

似乎您想要所有合同(的几个属性),每个合同都带有其ContractDate的日期。如果合同没有ContractDate,那么您想为Date使用默认值(在您的情况下为String.Empty)

您是对的,每当您有一个表项时,其中每个表项都包含来自另一个表的零个或多个项,并且您想要合并这两个表,就可以使用某种联接。

如果要使用每个项目以及一个和另一个项目,请使用加入。如果您希望每个项目都包含零个或多个其他项目,请使用 GroupJoin

在以下情况下,请使用GroupJoin:

  • 零个或多个学生的学校
  • 零个或多个订单的客户
  • 使用零个或多个ContractDate(在您的情况下:零个或一个)进行合同

如果需要,请使用Join:

  • 参加一所唯一学校的学生
  • 与客户下订单的订单
  • 与外键引用的合同的合同日期。

您遇到了问题,因为方向错误:您应该使用one of the overloads of GroupJoin而不是Join。

对于您而言,最好将重载与参数resultSelector一起使用:对于每个具有零个或多个ContractDates(在您的情况下为零或一个)的Contract,创建一个新对象:

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

    const字符串defaultContractDate = String.Empty; var contractWithTDates = contract.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运算符):如果FirstOrDefault的结果为非null,则使用此值;如果为null,则使用defaultContractDate。