c#字典一键多值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2101069/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
c# dictionary one key many values
提问by Marc G
I want to create a data store to allow me to store some data.
我想创建一个数据存储以允许我存储一些数据。
The first idea was to create a dictionary where you have 1 key with many values, so a bit like a one to many relationship.
第一个想法是创建一个字典,其中有一个包含多个值的键,所以有点像一对多的关系。
I think the dictionary only has 1 key value.
我认为字典只有 1 个键值。
How else could I store this information?
我还能如何存储这些信息?
回答by Oded
You can use a list for the second generic type. For example a dictionary of strings keyed by a string:
您可以将列表用于第二个泛型类型。例如,由字符串键控的字符串字典:
Dictionary<string, List<string>> myDict;
回答by Blorgbeard is out
You could use a Dictionary<TKey, List<TValue>>
.
你可以使用一个Dictionary<TKey, List<TValue>>
.
That would allow each key to reference a listof values.
这将允许每个键引用一个值列表。
回答by Maurits Rijk
You can have a dictionary with a collection (or any other type/class) as a value. That way you have a single key and you store the values in your collection.
您可以将一个带有集合(或任何其他类型/类)的字典作为值。这样你就有了一个键,你将值存储在你的集合中。
回答by Alastair Pitts
A .NET dictionary does only have a 1-to-1 relationship for keys and values. But that doesn't mean that a value can't be another array/list/dictionary.
.NET 字典对于键和值只有一对一的关系。但这并不意味着一个值不能是另一个数组/列表/字典。
I can't think of a reason to have a 1 to many relationship in a dictionary, but obviously there is one.
我想不出在字典中有一对多关系的理由,但显然有一个。
If you have different types of data that you want to store to a key, then that sounds like the ideal time to create your own class. Then you have a 1 to 1, but you have the value class storing more that 1 piece of data.
如果您想将不同类型的数据存储到一个键中,那么这听起来是创建您自己的类的理想时机。然后你有一个 1 比 1,但你有存储更多 1 条数据的值类。
回答by Tim Ridgely
Your dictionary's value type could be a List, or other class that holds multiple objects. Something like
字典的值类型可以是 List 或其他包含多个对象的类。就像是
Dictionary<int, List<string>>
for a Dictionary that is keyed by ints and holds a List of strings.
用于由整数键控并保存字符串列表的字典。
A main consideration in choosing the value type is what you'll be using the Dictionary for, if you'll have to do searching or other operations on the values, then maybe think about using a data structure that helps you do what you want -- like a HashSet.
选择值类型的一个主要考虑因素是您将使用字典的目的,如果您必须对值进行搜索或其他操作,那么也许可以考虑使用一种数据结构来帮助您做您想做的事- - 就像一个哈希集。
回答by GraemeF
Use a dictionary of lists (or another type of collection), for example:
使用列表字典(或其他类型的集合),例如:
var myDictionary = new Dictionary<string, IList<int>>();
myDictionary["My key"] = new List<int> {1, 2, 3, 4, 5};
回答by mbx
As of .net3.5+ instead of using a Dictionary<IKey, List<IValue>>
you can use a Lookup
from the Linq namespace:
从 .net3.5+ 开始,Dictionary<IKey, List<IValue>>
您可以使用Lookup
Linq 命名空间中的a而不是使用 a :
// lookup Order by payment status (1:m)
// would need something like Dictionary<Boolean, IEnumerable<Order>> orderIdByIsPayed
ILookup<Boolean, Order> byPayment = orderList.ToLookup(o => o.IsPayed);
IEnumerable<Order> payedOrders = byPayment[false];
From msdn:
从msdn:
A Lookup resembles a Dictionary. The difference is that a Dictionary maps keys to single values, whereas a Lookup maps keys to collections of values.
You can create an instance of a Lookup by calling ToLookup on an object that implements IEnumerable.
查找类似于字典。区别在于字典将键映射到单个值,而查找将键映射到值的集合。
您可以通过在实现 IEnumerable 的对象上调用 ToLookup 来创建 Lookup 的实例。
You may also want to read this answerto a related question. For more info, consult msdn.
您可能还需要阅读这个答案的相关问题。有关详细信息,请咨询msdn。
Full example:
完整示例:
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqLookupSpike
{
class Program
{
static void Main(String[] args)
{
// init
var orderList = new List<Order>();
orderList.Add(new Order(1, 1, 2010, true));//(orderId, customerId, year, isPayed)
orderList.Add(new Order(2, 2, 2010, true));
orderList.Add(new Order(3, 1, 2010, true));
orderList.Add(new Order(4, 2, 2011, true));
orderList.Add(new Order(5, 2, 2011, false));
orderList.Add(new Order(6, 1, 2011, true));
orderList.Add(new Order(7, 3, 2012, false));
// lookup Order by its id (1:1, so usual dictionary is ok)
Dictionary<Int32, Order> orders = orderList.ToDictionary(o => o.OrderId, o => o);
// lookup Order by customer (1:n)
// would need something like Dictionary<Int32, IEnumerable<Order>> orderIdByCustomer
ILookup<Int32, Order> byCustomerId = orderList.ToLookup(o => o.CustomerId);
foreach (var customerOrders in byCustomerId)
{
Console.WriteLine("Customer {0} ordered:", customerOrders.Key);
foreach (var order in customerOrders)
{
Console.WriteLine(" Order {0} is payed: {1}", order.OrderId, order.IsPayed);
}
}
// the same using old fashioned Dictionary
Dictionary<Int32, List<Order>> orderIdByCustomer;
orderIdByCustomer = byCustomerId.ToDictionary(g => g.Key, g => g.ToList());
foreach (var customerOrders in orderIdByCustomer)
{
Console.WriteLine("Customer {0} ordered:", customerOrders.Key);
foreach (var order in customerOrders.Value)
{
Console.WriteLine(" Order {0} is payed: {1}", order.OrderId, order.IsPayed);
}
}
// lookup Order by payment status (1:m)
// would need something like Dictionary<Boolean, IEnumerable<Order>> orderIdByIsPayed
ILookup<Boolean, Order> byPayment = orderList.ToLookup(o => o.IsPayed);
IEnumerable<Order> payedOrders = byPayment[false];
foreach (var payedOrder in payedOrders)
{
Console.WriteLine("Order {0} from Customer {1} is not payed.", payedOrder.OrderId, payedOrder.CustomerId);
}
}
class Order
{
// key properties
public Int32 OrderId { get; private set; }
public Int32 CustomerId { get; private set; }
public Int32 Year { get; private set; }
public Boolean IsPayed { get; private set; }
// additional properties
// private List<OrderItem> _items;
public Order(Int32 orderId, Int32 customerId, Int32 year, Boolean isPayed)
{
OrderId = orderId;
CustomerId = customerId;
Year = year;
IsPayed = isPayed;
}
}
}
}
Remark on Immutability
关于不变性的评论
By default, Lookups are kind of immutable and accessing the internal
s would involve reflection.
If you need mutability and don't want to write your own wrapper, you could use MultiValueDictionary
(formerly known as MultiDictionary
)
from corefxlab(formerly part ofMicrosoft.Experimental.Collections
which isn't updated anymore).
默认情况下,查找是不可变的,访问internal
s 将涉及反射。如果您需要可变性并且不想编写自己的包装器,您可以使用MultiValueDictionary
(以前称为MultiDictionary
)来自corefxlab(以前的一部分Microsoft.Experimental.Collections
不再更新)。
回答by Gisway
Use this:
用这个:
Dictionary<TKey, Tuple<TValue1, TValue2, TValue3, ...>>
回答by Ian Hays
Microsoft just added an official prelease version of exactly what you're looking for (called a MultiDictionary) available through NuGet here: https://www.nuget.org/packages/Microsoft.Experimental.Collections/
微软刚刚通过 NuGet 添加了您正在寻找的官方预发布版本(称为 MultiDictionary):https://www.nuget.org/packages/Microsoft.Experimental.Collections/
Info on usage and more details can be found through the official MSDN blog post here: http://blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx
有关使用的信息和更多详细信息可以通过此处的官方 MSDN 博客文章找到:http: //blogs.msdn.com/b/dotnet/archive/2014/06/20/would-you-like-a-multidictionary.aspx
I'm the developer for this package, so let me know either here or on MSDN if you have any questions about performance or anything.
我是这个包的开发者,所以如果你对性能有任何疑问,请在此处或在 MSDN 上告诉我。
Hope that helps.
希望有帮助。
Update
更新
The MultiValueDictionary
is now on the corefxlab repo, and you can get the NuGet package from thisMyGet feed.
在MultiValueDictionary
现在的corefxlab回购,你可以从获得NuGet包这个MyGet饲料。
回答by Shimmy Weitzhandler
Here's my approach to achieve this behavior.
这是我实现这种行为的方法。
For a more comprehensive solution involving ILookup<TKey, TElement>
, check out my other answer.
有关更全面的解决方案ILookup<TKey, TElement>
,请查看我的其他答案。
public abstract class Lookup<TKey, TElement> : KeyedCollection<TKey, ICollection<TElement>>
{
protected override TKey GetKeyForItem(ICollection<TElement> item) =>
item
.Select(b => GetKeyForItem(b))
.Distinct()
.SingleOrDefault();
protected abstract TKey GetKeyForItem(TElement item);
public void Add(TElement item)
{
var key = GetKeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
collection.Add(item);
else
Add(new List<TElement> { item });
}
public void Remove(TElement item)
{
var key = GetKeyForItem(item);
if (Dictionary != null && Dictionary.TryGetValue(key, out var collection))
{
collection.Remove(item);
if (collection.Count == 0)
Remove(key);
}
}
}
Usage:
用法:
public class Item
{
public string Key { get; }
public string Value { get; set; }
public Item(string key, string value = null) { Key = key; Value = value; }
}
public class Lookup : Lookup<string, Item>
{
protected override string GetKeyForItem(Item item) => item.Key;
}
static void Main(string[] args)
{
var toRem = new Item("1", "different");
var single = new Item("2", "single");
var lookup = new Lookup()
{
new Item("1", "hello"),
new Item("1", "hello2"),
new Item(""),
new Item("", "helloo"),
toRem,
single
};
lookup.Remove(toRem);
lookup.Remove(single);
}
Note: the key must be immutable (or remove and re-add upon key-change).
注意:密钥必须是不可变的(或者在密钥更改时删除并重新添加)。