您确实意识到,如果特定字典元素中列表的第二个元素具有匹配的 channelId,那么您会返回此列表的第一个元素,不是吗?
var otherList = new OtherItem[]
{
new OtherItem() {ChannelId = 1, ...}
}
var dictionary = new Dictionary<int, List<Channel>[]
{
{ 10, // Key
new List<Channel>() // Value
{
new Channel() {ChannelId = 100, Name = "100"},
new Channel() {ChannelId = 1, Name = "1"},
},
};
虽然第二个元素具有匹配的 ChannelId,但您返回第一个元素的名称。
无论如何,让我们假设这是您真正想要的。你是对的,你的功能不是很有效。
您的字典实现了IEnumerable<KeyValuePair<int, List<Channel>>。因此,foreach 中的每个x 都是KeyValuePair<int, List<Channel>。每个x.Value 都是List<Channel>。
因此,对于字典中的每个元素(即 KeyValuePair<int, List<Channel>),您获取完整列表,并使用 otherList 执行完整列表的完整内部连接,并获取结果的键KeyValuePair 和 KeyValuePair 中 List 的第一个元素。
即使您可能不使用完整的结果,而只使用第一个或前几个结果,因为 FirstOrDefault() 或 Take(3),您对字典中每个列表的每个元素都执行此操作。
确实,您的查询会更有效率。
当您在 OtherList 中使用 ChannelIds 只是为了找出它是否存在时,主要的改进之一是将 OtherList 的 ChannelIds 转换为您有优势的 HashSet<int>快速查找以检查 Dictionary 中某个值的 ChannelId 是否在 HashSet 中。
因此,对于字典中的每个元素,您只需检查列表中的每个 ChannelId 以查看其中一个是否在 HashSet 中。找到一个后,您可以停止并仅返回 List 的第一个元素和 Key。
我的解决方案是字典的扩展功能>。见Extension Methods Demystified
public static IEnumerable<NewObject> ExtractNewObjects(this Dictionary<int, List<Channel>> dictionary,
IEnumerable<OtherItem> otherList)
{
// I'll only use the ChannelIds of the otherList, so extract them
IEnumerable<int> otherChannelIds = otherList
.Select(otherItem => otherItem.ChannelId);
return dictionary.ExtractNewObjects(otherChannelIds);
}
这会调用其他的 ExtractNewobjects:
public static IEnumerable<NewObject> ExtractNewObjects(this Dictionary<int, List<Channel>> dictionary,
IEnumerable<int> otherChannelIds)
{
var channelIdsSet = new HashSet<int>(otherChannelIds));
// duplicate channelIds will be removed automatically
foreach (KeyValuePair<int, List<Channel>> keyValuePair in dictionary)
{
// is any ChannelId in the list also in otherChannelIdsSet?
// every keyValuePair.Value is a List<Channel>
// every Channel has a ChannelId
// channelId found if any of these ChannelIds in in the HashSet
bool channelIdFound = keyValuePair.Value
.Any(channel => otherChannelIdsSet.Contains(channel.ChannelId);
if (channelIdFound)
{
yield return new NewObject()
{
NewObjectYear = keyValuePair.Key,
NewObjectName = keyValuePair.Value
.Select(channel => channel.ChannelName)
.FirstOrDefault(),
};
}
}
}
用法:
IEnumerable<OtherItem> otherList = ...
Dictionary<int, List<Channel>> dictionary = ...
IEnumerable<Newobject> extractedNewObjects = dictionary.ExtractNewObjects(otherList);
var someNewObjects = extractedNewObjects
.Take(5) // here we see the benefit from the yield return
.ToList();
我们可以看到四个效率提升:
- 使用
HashSet<int> 可以非常快速地查找ChannelId 是否在OtherList 中
- 一旦我们在
HashSet 中找到匹配的Channelid,使用Any() 就会停止枚举List<Channel>
-
yield return 的使用使您不会在字典中枚举比实际使用的更多的元素。
- 在创建
NewObjectName 时使用Select 和FirstOrDefault 可防止List<Channel> 为空时出现异常