Вы понимаете, что если второй элемент списка в определенном элементе словаря имеет соответствующий идентификатор канала, вы возвращаете первый элемент этого списка, не так ли?
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"},
},
};
Хотя2-й элемент имеет соответствующий ChannelId, вы возвращаете Имя первого элемента.
В любом случае, давайте предположим, что это именно то, что вам действительно нужно.Вы правы, ваша функция не очень эффективна.
В вашем словаре реализовано IEnumerable<KeyValuePair<int, List<Channel>>
.Поэтому каждый x
в вашем foreach
является KeyValuePair<int, List<Channel>
.Каждый x.Value
является List<Channel>
.
Таким образом, для каждого элемента в вашем словаре (который является KeyValuePair<int, List<Channel>
), вы берете полный список и выполняете полное внутреннее объединение полного списка с помощью otherList
, и для результата вы берете ключ KeyValuePair
и первый элемент списка в KeyValuePair
.
И даже если вы можете использовать не полный результат, а только первыйили первые несколько из-за FirstOrDefault()
, или Take(3)
, вы делаете это для каждого элемента каждого списка в своем Словаре.
Действительно, ваш запрос может быть намного более эффективным.
Поскольку вы используете ChannelIds
в своем OtherList
только для того, чтобы выяснить, присутствует ли он, одним из основных улучшений было бы преобразование ChannelIds
из OtherList
в HashSet<int>
, где у вас есть быстрый быстрый поиск впроверьте, находится ли ChannelId одного из значений в вашем Словаре в HashSet
.
Так что для каждого элемента в вашем словаре, вам нужно только проверить каждый ChannelId
в списке, чтобы увидеть, является ли один изих в HashSet
.Как только вы нашли его, вы можете остановить и вернуть только первый элемент списка и ключ.
Мое решение - это функция расширения словаря>.См. Расширение методов расширения:
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
- , использование
Any()
прекращает перечисление List<Channel>
как только мы нашли соответствующий Channelid
в HashSet
- , использование
yield return
позволяет вам не перечислять больше элементов в своем словаре, чем вы фактически используете. - Использование
Select
и FirstOrDefault
при создании NewObjectName
предотвращает исключения, если List<Channel>
пусто