commit
20dac6d6b8
|
@ -904,7 +904,7 @@ namespace Emby.Server.Implementations
|
||||||
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager);
|
PlaylistManager = new PlaylistManager(LibraryManager, FileSystemManager, LibraryMonitor, LoggerFactory, UserManager, ProviderManager);
|
||||||
RegisterSingleInstance(PlaylistManager);
|
RegisterSingleInstance(PlaylistManager);
|
||||||
|
|
||||||
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, ProviderManager, FileSystemManager, () => ChannelManager);
|
LiveTvManager = new LiveTvManager(this, ServerConfigurationManager, LoggerFactory, ItemRepository, ImageProcessor, UserDataManager, DtoService, UserManager, LibraryManager, TaskManager, LocalizationManager, JsonSerializer, FileSystemManager, () => ChannelManager);
|
||||||
RegisterSingleInstance(LiveTvManager);
|
RegisterSingleInstance(LiveTvManager);
|
||||||
|
|
||||||
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
|
UserViewManager = new UserViewManager(LibraryManager, LocalizationManager, UserManager, ChannelManager, LiveTvManager, ServerConfigurationManager);
|
||||||
|
|
|
@ -70,7 +70,8 @@ namespace Emby.Server.Implementations.Collections
|
||||||
return null;
|
return null;
|
||||||
})
|
})
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -620,7 +620,8 @@ namespace Emby.Server.Implementations.Dto
|
||||||
}
|
}
|
||||||
|
|
||||||
}).Where(i => i != null)
|
}).Where(i => i != null)
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
|
.ToDictionary(i => i.Name, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
for (var i = 0; i < people.Count; i++)
|
for (var i = 0; i < people.Count; i++)
|
||||||
|
|
|
@ -277,14 +277,21 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||||
lock (_libraryChangedSyncLock)
|
lock (_libraryChangedSyncLock)
|
||||||
{
|
{
|
||||||
// Remove dupes in case some were saved multiple times
|
// Remove dupes in case some were saved multiple times
|
||||||
var foldersAddedTo = _foldersAddedTo.DistinctBy(i => i.Id).ToList();
|
var foldersAddedTo = _foldersAddedTo
|
||||||
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var foldersRemovedFrom = _foldersRemovedFrom.DistinctBy(i => i.Id).ToList();
|
var foldersRemovedFrom = _foldersRemovedFrom
|
||||||
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var itemsUpdated = _itemsUpdated
|
var itemsUpdated = _itemsUpdated
|
||||||
.Where(i => !_itemsAdded.Contains(i))
|
.Where(i => !_itemsAdded.Contains(i))
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
.ToList();
|
.Select(x => x.First())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);
|
SendChangeNotifications(_itemsAdded.ToList(), itemsUpdated, _itemsRemoved.ToList(), foldersAddedTo, foldersRemovedFrom, CancellationToken.None);
|
||||||
|
|
||||||
|
|
|
@ -121,7 +121,8 @@ namespace Emby.Server.Implementations.EntryPoints
|
||||||
var user = _userManager.GetUserById(userId);
|
var user = _userManager.GetUserById(userId);
|
||||||
|
|
||||||
var dtoList = changedItems
|
var dtoList = changedItems
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
.Select(i =>
|
.Select(i =>
|
||||||
{
|
{
|
||||||
var dto = _userDataManager.GetUserDataDto(i, user);
|
var dto = _userDataManager.GetUserDataDto(i, user);
|
||||||
|
|
|
@ -146,8 +146,8 @@ namespace Emby.Server.Implementations.IO
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
.Select(GetAffectedBaseItem)
|
.Select(GetAffectedBaseItem)
|
||||||
.Where(item => item != null)
|
.Where(item => item != null)
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
.ToList();
|
.Select(x => x.First());
|
||||||
|
|
||||||
foreach (var item in itemsToRefresh)
|
foreach (var item in itemsToRefresh)
|
||||||
{
|
{
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.Threading.Tasks;
|
||||||
using Emby.Server.Implementations.Library;
|
using Emby.Server.Implementations.Library;
|
||||||
using MediaBrowser.Common.Configuration;
|
using MediaBrowser.Common.Configuration;
|
||||||
using MediaBrowser.Common.Extensions;
|
using MediaBrowser.Common.Extensions;
|
||||||
using MediaBrowser.Common.Net;
|
|
||||||
using MediaBrowser.Common.Progress;
|
using MediaBrowser.Common.Progress;
|
||||||
using MediaBrowser.Controller;
|
using MediaBrowser.Controller;
|
||||||
using MediaBrowser.Controller.Channels;
|
using MediaBrowser.Controller.Channels;
|
||||||
|
@ -24,7 +23,6 @@ using MediaBrowser.Controller.Sorting;
|
||||||
using MediaBrowser.Model.Dto;
|
using MediaBrowser.Model.Dto;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Events;
|
using MediaBrowser.Model.Events;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.Globalization;
|
using MediaBrowser.Model.Globalization;
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.LiveTv;
|
using MediaBrowser.Model.LiveTv;
|
||||||
|
@ -48,7 +46,6 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
private readonly ILibraryManager _libraryManager;
|
private readonly ILibraryManager _libraryManager;
|
||||||
private readonly ITaskManager _taskManager;
|
private readonly ITaskManager _taskManager;
|
||||||
private readonly IJsonSerializer _jsonSerializer;
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
private readonly IProviderManager _providerManager;
|
|
||||||
private readonly Func<IChannelManager> _channelManager;
|
private readonly Func<IChannelManager> _channelManager;
|
||||||
|
|
||||||
private readonly IDtoService _dtoService;
|
private readonly IDtoService _dtoService;
|
||||||
|
@ -85,7 +82,6 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
ITaskManager taskManager,
|
ITaskManager taskManager,
|
||||||
ILocalizationManager localization,
|
ILocalizationManager localization,
|
||||||
IJsonSerializer jsonSerializer,
|
IJsonSerializer jsonSerializer,
|
||||||
IProviderManager providerManager,
|
|
||||||
IFileSystem fileSystem,
|
IFileSystem fileSystem,
|
||||||
Func<IChannelManager> channelManager)
|
Func<IChannelManager> channelManager)
|
||||||
{
|
{
|
||||||
|
@ -97,7 +93,6 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
_taskManager = taskManager;
|
_taskManager = taskManager;
|
||||||
_localization = localization;
|
_localization = localization;
|
||||||
_jsonSerializer = jsonSerializer;
|
_jsonSerializer = jsonSerializer;
|
||||||
_providerManager = providerManager;
|
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_dtoService = dtoService;
|
_dtoService = dtoService;
|
||||||
_userDataManager = userDataManager;
|
_userDataManager = userDataManager;
|
||||||
|
@ -2469,7 +2464,8 @@ namespace Emby.Server.Implementations.LiveTv
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.Where(i => i.IsVisibleStandalone(user))
|
.Where(i => i.IsVisibleStandalone(user))
|
||||||
.SelectMany(i => _libraryManager.GetCollectionFolders(i))
|
.SelectMany(i => _libraryManager.GetCollectionFolders(i))
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
.OrderBy(i => i.SortName)
|
.OrderBy(i => i.SortName)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
|
@ -111,7 +111,8 @@ namespace Emby.Server.Implementations.Networking
|
||||||
.OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
|
.OrderBy(i => i.AddressFamily == AddressFamily.InterNetwork ? 0 : 1)
|
||||||
.ThenBy(i => listClone.IndexOf(i))
|
.ThenBy(i => listClone.IndexOf(i))
|
||||||
.Where(FilterIpAddress)
|
.Where(FilterIpAddress)
|
||||||
.DistinctBy(i => i.ToString())
|
.GroupBy(i => i.ToString())
|
||||||
|
.Select(x => x.First())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -429,7 +430,8 @@ namespace Emby.Server.Implementations.Networking
|
||||||
return new List<IPAddress>();
|
return new List<IPAddress>();
|
||||||
}
|
}
|
||||||
|
|
||||||
}).DistinctBy(i => i.ToString())
|
}).GroupBy(i => i.ToString())
|
||||||
|
.Select(x => x.First())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Playlists;
|
using MediaBrowser.Controller.Playlists;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
using MediaBrowser.Model.Querying;
|
using MediaBrowser.Model.Querying;
|
||||||
|
|
||||||
|
@ -64,7 +63,8 @@ namespace Emby.Server.Implementations.Playlists
|
||||||
})
|
})
|
||||||
.Where(i => i != null)
|
.Where(i => i != null)
|
||||||
.OrderBy(i => Guid.NewGuid())
|
.OrderBy(i => Guid.NewGuid())
|
||||||
.DistinctBy(i => i.Id)
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ using MediaBrowser.Controller.Entities.TV;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.Providers;
|
using MediaBrowser.Controller.Providers;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
using MediaBrowser.Model.IO;
|
using MediaBrowser.Model.IO;
|
||||||
|
|
||||||
namespace Emby.Server.Implementations.UserViews
|
namespace Emby.Server.Implementations.UserViews
|
||||||
|
@ -83,7 +82,8 @@ namespace Emby.Server.Implementations.UserViews
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
}).DistinctBy(i => i.Id);
|
}).GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First());
|
||||||
|
|
||||||
if (isUsingCollectionStrip)
|
if (isUsingCollectionStrip)
|
||||||
{
|
{
|
||||||
|
|
|
@ -551,7 +551,8 @@ namespace MediaBrowser.Api.Library
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
DefaultEnabled = IsSaverEnabledByDefault(i.Name, types, isNewLibrary)
|
DefaultEnabled = IsSaverEnabledByDefault(i.Name, types, isNewLibrary)
|
||||||
})
|
})
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
result.MetadataReaders = plugins
|
result.MetadataReaders = plugins
|
||||||
|
@ -561,7 +562,8 @@ namespace MediaBrowser.Api.Library
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
DefaultEnabled = true
|
DefaultEnabled = true
|
||||||
})
|
})
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
result.SubtitleFetchers = plugins
|
result.SubtitleFetchers = plugins
|
||||||
|
@ -571,7 +573,8 @@ namespace MediaBrowser.Api.Library
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
DefaultEnabled = true
|
DefaultEnabled = true
|
||||||
})
|
})
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
var typeOptions = new List<LibraryTypeOptions>();
|
var typeOptions = new List<LibraryTypeOptions>();
|
||||||
|
@ -593,7 +596,8 @@ namespace MediaBrowser.Api.Library
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
DefaultEnabled = IsMetadataFetcherEnabledByDefault(i.Name, type, isNewLibrary)
|
DefaultEnabled = IsMetadataFetcherEnabledByDefault(i.Name, type, isNewLibrary)
|
||||||
})
|
})
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToArray(),
|
.ToArray(),
|
||||||
|
|
||||||
ImageFetchers = plugins
|
ImageFetchers = plugins
|
||||||
|
@ -604,7 +608,8 @@ namespace MediaBrowser.Api.Library
|
||||||
Name = i.Name,
|
Name = i.Name,
|
||||||
DefaultEnabled = IsImageFetcherEnabledByDefault(i.Name, type, isNewLibrary)
|
DefaultEnabled = IsImageFetcherEnabledByDefault(i.Name, type, isNewLibrary)
|
||||||
})
|
})
|
||||||
.DistinctBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
.GroupBy(i => i.Name, StringComparer.OrdinalIgnoreCase)
|
||||||
|
.Select(x => x.First())
|
||||||
.ToArray(),
|
.ToArray(),
|
||||||
|
|
||||||
SupportedImageTypes = plugins
|
SupportedImageTypes = plugins
|
||||||
|
|
|
@ -268,7 +268,8 @@ namespace MediaBrowser.Api.Movies
|
||||||
EnableGroupByMetadataKey = true,
|
EnableGroupByMetadataKey = true,
|
||||||
DtoOptions = dtoOptions
|
DtoOptions = dtoOptions
|
||||||
|
|
||||||
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
}).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
||||||
|
.Select(x => x.First())
|
||||||
.Take(itemLimit)
|
.Take(itemLimit)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
@ -308,7 +309,8 @@ namespace MediaBrowser.Api.Movies
|
||||||
EnableGroupByMetadataKey = true,
|
EnableGroupByMetadataKey = true,
|
||||||
DtoOptions = dtoOptions
|
DtoOptions = dtoOptions
|
||||||
|
|
||||||
}).DistinctBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
}).GroupBy(i => i.GetProviderId(MetadataProviders.Imdb) ?? Guid.NewGuid().ToString("N"))
|
||||||
|
.Select(x => x.First())
|
||||||
.Take(itemLimit)
|
.Take(itemLimit)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|
|
@ -335,7 +335,11 @@ namespace MediaBrowser.Controller.Entities
|
||||||
.OfType<Folder>()
|
.OfType<Folder>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
return PhysicalLocations.Where(i => !FileSystem.AreEqual(i, Path)).SelectMany(i => GetPhysicalParents(i, rootChildren)).DistinctBy(i => i.Id);
|
return PhysicalLocations
|
||||||
|
.Where(i => !FileSystem.AreEqual(i, Path))
|
||||||
|
.SelectMany(i => GetPhysicalParents(i, rootChildren))
|
||||||
|
.GroupBy(x => x.Id)
|
||||||
|
.Select(x => x.First());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
|
private IEnumerable<Folder> GetPhysicalParents(string path, List<Folder> rootChildren)
|
||||||
|
|
|
@ -270,7 +270,7 @@ namespace MediaBrowser.Controller.Entities.TV
|
||||||
// This depends on settings for that series
|
// This depends on settings for that series
|
||||||
// When this happens, remove the duplicate from season 0
|
// When this happens, remove the duplicate from season 0
|
||||||
|
|
||||||
return allEpisodes.DistinctBy(i => i.Id).Reverse();
|
return allEpisodes.GroupBy(i => i.Id).Select(x => x.First()).Reverse();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress<double> progress, CancellationToken cancellationToken)
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MediaBrowser.Controller.Extensions;
|
using MediaBrowser.Controller.Extensions;
|
||||||
using MediaBrowser.Model.Extensions;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Controller.Library
|
namespace MediaBrowser.Controller.Library
|
||||||
{
|
{
|
||||||
|
@ -14,13 +14,11 @@ namespace MediaBrowser.Controller.Library
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
//return name;
|
|
||||||
return name.RemoveDiacritics();
|
return name.RemoveDiacritics();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
|
public static IEnumerable<string> DistinctNames(this IEnumerable<string> names)
|
||||||
{
|
=> names.GroupBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase)
|
||||||
return names.DistinctBy(RemoveDiacritics, StringComparer.OrdinalIgnoreCase);
|
.Select(x => x.First());
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
// TODO: @bond Remove
|
|
||||||
namespace MediaBrowser.Model.Extensions
|
|
||||||
{
|
|
||||||
// MoreLINQ - Extensions to LINQ to Objects
|
|
||||||
// Copyright (c) 2008 Jonathan Skeet. All rights reserved.
|
|
||||||
//
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
|
|
||||||
public static class LinqExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all distinct elements of the given source, where "distinctness"
|
|
||||||
/// is determined via a projection and the default equality comparer for the projected type.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This operator uses deferred execution and streams the results, although
|
|
||||||
/// a set of already-seen keys is retained. If a key is seen multiple times,
|
|
||||||
/// only the first element with that key is returned.
|
|
||||||
/// </remarks>
|
|
||||||
/// <typeparam name="TSource">Type of the source sequence</typeparam>
|
|
||||||
/// <typeparam name="TKey">Type of the projected element</typeparam>
|
|
||||||
/// <param name="source">Source sequence</param>
|
|
||||||
/// <param name="keySelector">Projection for determining "distinctness"</param>
|
|
||||||
/// <returns>A sequence consisting of distinct elements from the source sequence,
|
|
||||||
/// comparing them by the specified key projection.</returns>
|
|
||||||
|
|
||||||
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
|
|
||||||
Func<TSource, TKey> keySelector)
|
|
||||||
{
|
|
||||||
return source.DistinctBy(keySelector, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all distinct elements of the given source, where "distinctness"
|
|
||||||
/// is determined via a projection and the specified comparer for the projected type.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// This operator uses deferred execution and streams the results, although
|
|
||||||
/// a set of already-seen keys is retained. If a key is seen multiple times,
|
|
||||||
/// only the first element with that key is returned.
|
|
||||||
/// </remarks>
|
|
||||||
/// <typeparam name="TSource">Type of the source sequence</typeparam>
|
|
||||||
/// <typeparam name="TKey">Type of the projected element</typeparam>
|
|
||||||
/// <param name="source">Source sequence</param>
|
|
||||||
/// <param name="keySelector">Projection for determining "distinctness"</param>
|
|
||||||
/// <param name="comparer">The equality comparer to use to determine whether or not keys are equal.
|
|
||||||
/// If null, the default equality comparer for <c>TSource</c> is used.</param>
|
|
||||||
/// <returns>A sequence consisting of distinct elements from the source sequence,
|
|
||||||
/// comparing them by the specified key projection.</returns>
|
|
||||||
|
|
||||||
public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source,
|
|
||||||
Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
|
||||||
{
|
|
||||||
if (source == null) throw new ArgumentNullException(nameof(source));
|
|
||||||
if (keySelector == null) throw new ArgumentNullException(nameof(keySelector));
|
|
||||||
return DistinctByImpl(source, keySelector, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<TSource> DistinctByImpl<TSource, TKey>(IEnumerable<TSource> source,
|
|
||||||
Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer)
|
|
||||||
{
|
|
||||||
var knownKeys = new HashSet<TKey>(comparer);
|
|
||||||
foreach (var element in source)
|
|
||||||
{
|
|
||||||
if (knownKeys.Add(keySelector(element)))
|
|
||||||
{
|
|
||||||
yield return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user