大家好,我有一个要求,我必须分配多个键,为了多个键,我必须分配多个值
我的要求如下。我为每位员工提供EmpID
,PayYr
和PayID
。
假设我得到的数据如下:
EmpID 1000 1000 1000 1000
PayYr 2011 2011 2011 2012
PayID 1 2 3 1
我想拥有我的字典,以便具有键值结果的字典如下:
1000 - 2011 - 1,2,3
1000 - 2012 - 1
我尝试了以下内容
public struct Tuple<T1, T2>
{
public readonly T1 Item1;
public readonly T2 Item2;
public Tuple(T1 item1, T2 item2)
{
Item1 = item1;
Item2 = item2;
}
}
示例代码
for (int empcnt = 0; empcnt < iEmpID.Length; empcnt++)
{
for (int yrcnt = 0; yrcnt < ipayYear.Length; yrcnt++)
{
List<int> lst1 = new List<int>();
var key1 = new Tuple<int, int>(iEmpID[empcnt], ipayYear[yrcnt]);
if (!dictAddValues.ContainsKey(key1))
{
dictAddValues.Add(key1, lst1);
lst1.Add(lst[yrcnt]);
}
}
}
但我没有按照我的要求得到我的结果,所以任何人都可以帮助我。
答案 0 :(得分:3)
就个人而言,我可能会使用词典词典,例如IDictionary<int, IDictionary<int, IList<int>>>
。不是我不完全确定您打算如何访问或促进这些数据; 将对我的建议效率产生很大影响。从好的方面来说,它可以 - 相对容易地 - 访问数据,当且仅当按照您设置词典的顺序访问它时。
(第二个想法,只是类型声明本身是如此丑陋和毫无意义,你可能想跳过我上面所说的。)
如果您是相当随机地访问字段,可能需要使用简单的非规范化ICollection<Tuple<int, int, int>>
(或等效的)来完成这一操作,并根据需要在应用程序的其他部分进行聚合。 LINQ可以在这里提供很多帮助,特别是它的聚合,分组和查找功能。
更新:希望这可以澄清:
var outerDictionary = new Dictionary<int, Dictionary<int, List<int>>>();
/* fill initial values
* assuming that you get your data row by row from an ADO.NET data source, EF, or something similar. */
foreach (var row in rows) {
var employeeId = (int) row["EmpID"];
var payYear = (int) row["PayYr"];
var payId = (int) row["PayID"];
Dictionary<int, int> innerDictionary;
if (!outerDictionary.TryGet(employeeId, out innerDictionary)) {
innerDictionary = new Dictionary<int, int>();
outerDictionary.Add(employeeId, innerDictionary);
}
List<int> list;
if (!innerDictionary.TryGet(payYear)) {
list = new List<int>();
innerDictionary.Add(payYear, list);
}
list.Add(payId);
}
/* now use it, e.g.: */
var data = outerDictionary[1000][2011]; // returns a list with { 1, 2, 3 }
虽然带着一粒盐;见评论。
答案 1 :(得分:1)
我认为你错过了Comparer这件作品。看看下面的文章是否有帮助。
带自定义键的词典
http://www.codeproject.com/Articles/23610/Dictionary-with-a-Custom-Key
答案 2 :(得分:1)
如果密钥是该类的一部分,则使用KeyedCollection 它是一个字典,其中键是从对象派生的 在封面下它是字典。 D不必重复键和值中的键 为什么键中的键与值不一样。不必在内存中复制相同的信息。
KeyedCollection类
公开复合键的索引器
using System.Collections.ObjectModel;
namespace IntIntKeyedCollection
{
class Program
{
static void Main(string[] args)
{
UInt16UInt16O Emp1 = new UInt16UInt16O(34, 1990);
Emp1.PayIDs.Add(1);
Emp1.PayIDs.Add(2);
UInt16UInt16O Emp2 = new UInt16UInt16O(34, 1990, new List<byte>{3,4});
if (Emp1 == Emp2) Console.WriteLine("same");
if (Emp1.Equals(Emp2)) Console.WriteLine("Equals");
Console.WriteLine("Emp1.GetHashCode " + Emp1.GetHashCode().ToString());
UInt16UInt16OCollection Employees = new UInt16UInt16OCollection();
Employees.Add(Emp1);
//this would fail
//Employees.Add(Emp2);
Employees.Add(new UInt16UInt16O(35, 1991, new List<byte> { 1 } ));
Employees.Add(new UInt16UInt16O(35, 1992, new List<byte> { 1, 2 } ));
Employees.Add(new UInt16UInt16O(36, 1992));
Console.WriteLine(Employees.Count.ToString());
// reference by ordinal postion (note the is not the long key)
Console.WriteLine(Employees[0].GetHashCode().ToString());
// reference by Int32 Int32
Console.WriteLine(Employees[35, 1991].GetHashCode().ToString());
Console.WriteLine("foreach");
foreach (UInt16UInt16O emp in Employees)
{
Console.WriteLine(string.Format("HashCode {0} EmpID {1} Year {2} NumCodes {3}", emp.GetHashCode(), emp.EmpID, emp.Year, emp.PayIDs.Count.ToString()));
}
Console.WriteLine("sorted");
foreach (UInt16UInt16O emp in Employees.OrderBy(e => e.EmpID).ThenBy(e => e.Year))
{
Console.WriteLine(string.Format("HashCode {0} EmpID {1} Year {2} NumCodes {3}", emp.GetHashCode(), emp.EmpID, emp.Year, emp.PayIDs.Count.ToString()));
}
}
public class UInt16UInt16OCollection : KeyedCollection<UInt16UInt16S, UInt16UInt16O>
{
// This parameterless constructor calls the base class constructor
// that specifies a dictionary threshold of 0, so that the internal
// dictionary is created as soon as an item is added to the
// collection.
//
public UInt16UInt16OCollection() : base(null, 0) { }
// This is the only method that absolutely must be overridden,
// because without it the KeyedCollection cannot extract the
// keys from the items.
//
protected override UInt16UInt16S GetKeyForItem(UInt16UInt16O item)
{
// In this example, the key is the part number.
return item.UInt16UInt16S;
}
// indexer
public UInt16UInt16O this[UInt16 EmpID, UInt16 Year]
{
get { return this[new UInt16UInt16S(EmpID, Year)]; }
}
}
public struct UInt16UInt16S
{ // required as KeyCollection Key must be a single item
// but you don't reaaly need to interact with Int32Int32s
public readonly UInt16 EmpID, Year;
public UInt16UInt16S(UInt16 empID, UInt16 year) { this.EmpID = empID; this.Year = year; }
}
public class UInt16UInt16O : Object
{
// implement you properties
public UInt16UInt16S UInt16UInt16S { get; private set; }
public UInt16 EmpID { get { return UInt16UInt16S.EmpID; } }
public UInt16 Year { get { return UInt16UInt16S.Year; } }
public List<byte> PayIDs { get; set; }
public override bool Equals(Object obj)
{
//Check for null and compare run-time types.
if (obj == null || !(obj is UInt16UInt16O)) return false;
UInt16UInt16O item = (UInt16UInt16O)obj;
return (this.EmpID == item.EmpID && this.Year == item.Year);
}
public override int GetHashCode() { return ((UInt32)EmpID << 16 | Year).GetHashCode() ; }
public UInt16UInt16O(UInt16 EmpID, UInt16 Year)
{
UInt16UInt16S uInt16UInt16S = new UInt16UInt16S(EmpID, Year);
this.UInt16UInt16S = uInt16UInt16S;
PayIDs = new List<byte>();
}
public UInt16UInt16O(UInt16 EmpID, UInt16 Year, List<byte> PayIDs)
{
UInt16UInt16S uInt16UInt16S = new UInt16UInt16S(EmpID, Year);
this.UInt16UInt16S = uInt16UInt16S;
this.PayIDs = PayIDs;
}
}
}
}
答案 3 :(得分:0)
我不是100%确定要用作密钥的完全数据。我想2? 2整数值?这就是我将在下面假设的,但如果您想要三个或类型不同,只需相应调整。我建议如下(步骤1是必要的,第2步是可选的,但我会这样做)
第1步创建自己的密钥结构,用作标准字典中的密钥。为它作为键的值提供2个属性(或三个,无论如何),和/或构造函数接受/设置这些值。
指定GetHashCode方法。类似的东西:
public override int GetHashCode()
{
unchecked
{
return (_empId * 397) ^ _payYr;
}
}
注意:是的,您可以使用元组。元组。 。 。并不像第一个看起来那么酷。您的属性名称将是Item1等。不是很清楚。而且你经常最终想要覆盖并尽快添加内容。从头开始。
像这样: public struct PayKey {
private int _empId
private int _payYr;
public PayKey (int empId, int payYr) {
_empId = empId;
_payYr = payYr;
}
public override int GetHashCode()
{
{
return (_empId * 83) ^ _payYr;
}
}
}
注意:如果要在组合键中使用的任何多个值都是引用类型,则应该创建一个类而不是结构。如果是这样,您还需要覆盖Equals
才能使其作为字典键正常工作。
public override bool Equals( object pkMaybe ){
if( pkMaybe is PayKey ) {
PayKey pk = (PayKey) pkMaybe ;
return _empId = pk.EmpId && _payYr = pk.PayYr;
}
else {
return false;
}
}
(并为您的键值添加公共属性,如果您还没有。)
或者,如果您按照我在下面提到的那样创建自定义词典,那么使用IEqualityComparer会很方便。 (基本上,如果你使用一个类作为你的键,你必须确保字典会看到两个相同的PayKey对象为“相等”。默认情况下,即使值相等,它们也是对不同对象的引用,因此框架会考虑他们不等于)
第2步:创建一个继承自Dictionary的类。再给它两个方法:
答案 4 :(得分:0)
您需要在Tuple
结构中实现Equals和GetHashCode:
public override bool Equals(object obj)
{
if (!(obj is Tuple<T1, T2>))
return false;
var t = (Tuple<T1, T2>)obj
return (this.Item1 == t.Item1 && this.Item2 == t.Item2);
}
public override int GetHashCode()
{
return (Item1 ^ Item2 );
}
答案 5 :(得分:0)
尝试从包含MultiValueDictionary类型的microsoft查看https://www.nuget.org/packages/Microsoft.Experimental.Collections。
MultiValueDictionary是一个关联单个字典的通用字典 具有一个或多个值的键。可以添加和删除值 独立地