c# - 使用 C# 中的字典在同一类中使用某些自定义类属性作为另一个属性(形成为值)的唯一键
问题描述
我有一个类类型,如下所示的 ValueSetting,我正在尝试迭代 List<ValueSetting>,以便对于列表中 param1、param2、param3 的所有常见条目,我必须对每个 param4 执行特定操作。让我解释 。在下表中,带有红色箭头标记的条目 (param1, param2, param3) 应该类似于 param4(500, 600) 的 list< values > 的键。所以巩固他们
10, 富, abc => (500, 600)
20, 嘘, abc =>( 500, 600)
30, 富, abc => (500)
那么,这是我可以将 param1、param2、param3 作为 List< param4 values > 的键放入字典中的吗?这是怎么做的?还是有更好的方法来存储它们而不是字典?
public class ValueSetting
{
public int param1;
public string param2;
public string param3;
public int param4;
}
解决方案
LINQ ToLookup method
可以使用您要求的方式来构造数据。来自 MSDN:
该
ToLookup
方法返回一个Lookup
,一个将键映射到值集合的一对多字典。ALookup
与 a 不同Dictionary
,后者执行键到单个值的一对一映射。
要创建Lookup
usingToLookup
方法,我们应该定义:
key
具有重写GetHashCode
和Equals
方法的类;此类key
将定义如何对输入数据进行分组;keySelector
这将用于从输入数据创建密钥;elementSelector
这将用于为适当的键选择值。
第一种方法:使用匿名类型作为键。
我们可以使用匿名类型作为键来创建一个Lookup
. Anonymous types
自动实现GetHashCode
和Equals
。来自 MSDN:
因为匿名类型的 Equals 和 GetHashCode 方法是根据属性的 Equals 和 GetHashCode 方法定义的,所以相同匿名类型的两个实例只有在它们的所有属性都相等时才相等。
以下是我们如何创建Lookup
usinganonymous type
作为键:
var list = new List<ValueSetting>
{
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 30, param2 = "foo", param3 = "abc", param4 = 500},
};
var lookup = list.ToLookup(
vs => new {vs.param1, vs.param2, vs.param3}, // Group key.
vs => vs.param4); // Group values.
foreach (var item in lookup)
{
Console.WriteLine("{0} => ({1})", item.Key, string.Join(", ", item.Select(i => i)));
}
如果您打算Lookup
在单个方法中使用这种方法很方便,因为匿名类型的对象不能从该方法返回并作为参数传递给另一个方法。
第二种方法:引入一个关键类。
另一种方法是定义一个将用作分组键的类。在这个类中,我们应该覆盖GetHashCode
和Equals
方法。如果您使用 Visual Studio 2015 或更高版本,则可以自动生成这些成员。下面是我们如何定义这样的类:
public class Key
{
public int param1;
public string param2;
public string param3;
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
Key other = (Key) obj;
Key other = (Key) obj;
return param1 == other.param1 &&
string.Equals(param2, other.param2) &&
string.Equals(param3, other.param3);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = param1;
hashCode = (hashCode * 397) ^ (param2 != null ? param2.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ (param3 != null ? param3.GetHashCode() : 0);
return hashCode;
}
}
}
然后使用这个关键类,我们可以创建一个Lookup
:
var list = new List<ValueSetting>
{
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 500},
new ValueSetting {param1 = 10, param2 = "foo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 20, param2 = "boo", param3 = "abc", param4 = 600},
new ValueSetting {param1 = 30, param2 = "foo", param3 = "abc", param4 = 500},
};
ILookup<Key, int> lookup = list.ToLookup(
vs => new Key {param1 = vs.param1, param2 = vs.param2, param3 = vs.param3}, // Group key.
vs => vs.param4); // Group values.
foreach (IGrouping<Key, int> item in lookup)
{
Console.WriteLine("{0}, {1}, {2} => ({3})",
item.Key.param1, item.Key.param2, item.Key.param3,
string.Join(", ", item.Select(i => i)));
}
如果您想Lookup
从方法返回,或将其作为参数传递给另一个方法,或存储为类的属性,则可以使用此方法(在其他情况下,创建时Lookup
必须在创建它的方法之外使用)。
推荐阅读
- javascript - Jest 测试用例失败 - ReferenceError: Office is not defined
- gwt - GWT JsInterop - 在 JavaScript 中扩展 Java 接口
- c# - 如何从与 C# 中的 UI 线程不同的线程访问 HttpContext.Request.Cookie?
- python-3.x - SyntaxError:if 语句时语法无效
- assembly - 链接 C 文件后无法让 QEMU 引导我的引导加载程序
- android - 有时,ConflatedBroadcastChannel 会在没有任何操作的情况下触发最近的值
- iis - iis 将 https://example.com/default.aspx/default.aspx 的 url 重写为 https://example.com
- docker - 当 Minikube (k8s) 中的 Pod 声明卷时,如何强制所有这些卷实际上位于裸机*主机*上的某个磁盘上?
- git - 将两个合并合并为一个(或者,我可以更改提交的父级吗?)
- java - FTP 文件下载中的 Apache Vfs 错误“无法复制文件名,因为它不存在