Reputation: 13
I'm trying to write a method for a project which takes any number of lists as parameters, and returns a new list containing terms which ALL of those lists share. I have functional code, but I'd much prefer to use the params keyword rather than having to create a list of lists which holds all the lists I want to compare.
static List<T> Shared<T>(List<T> first, List<T> second)
{
List<T> result = new List<T>();
foreach (T item in first)
if (second.Contains(item) && !result.Contains(item)) result.Add(item);
return result;
}
static List<T> Shared<T>(List<List<T>> lists)
{
List<T> result = lists.First();
foreach (List<T> list in lists.Skip(1))
{
result = Shared<T>(result, list);
}
return result;
}
Is my current code, which works fine comparing two lists, but in order to compare more than two lists I have to either create a new list like:
List<int> nums1 = new List<int> { 1, 2, 3, 4, 5, 6 };
List<int> nums2 = new List<int> { 1, 2, 3 };
List<int> nums3 = new List<int> { 6, 5, 3, 2 };
List<int> listOfLists = Shared<int>(new List<List<int>> {nums1, nums2, nums3});
foreach (int item in listOfLists)
Console.WriteLine(item);
//Writes 2 and 3
etc. I would really wish to just be able to use Shared(list1, list2, list3, list4...) instead, even if this code is already somewhat functional. Currently any attempts to use a params version complains that "No overload for method 'Shared' takes N arguments"
Also I know my code could probably be done more efficiently, so I'd be glad to see suggestions on that too but primarily I need to get my head around why using params isn't working - if it's even possible.
Upvotes: 1
Views: 73
Reputation: 800
Building on the response of @Selman22 who proposed the method signature, you could alternatively use this LINQ query, to achieve the desired result.
static List<T> Shared<T>(params List<T>[] lists)
{
return
lists.Skip(1).Aggregate( // Skip first array item, because we use it as a seed anyway
lists.FirstOrDefault(), // Seed the accumulator with first item in the array
(accumulator, currentItem) => accumulator.Intersect(currentItem).ToList()); // Intersect each item with the previous results
}
We skip the first item that is being used as the seed for the accumulator, and do an intersect with the accumulator for each item in the given params array, since only the items that are contained in ALL the lists are kept in the accumulator result.
To test it out, you can use
Shared(nums1, nums2, nums3).ForEach(r => Console.WriteLine(r));
Upvotes: 0
Reputation: 101681
Are you looking for this?
static List<T> Shared<T>(params List<T>[] lists)
The params
parameter must always have an array type, but it can be an array of Lists.
Upvotes: 5
Reputation:
It can be done quiet easily:
using System.Linq;
// ..
static List<T> Shared<T>(params List<T>[] lists)
{
if (lists == null)
{
throw new ArgumentNullException("lists");
}
return Shared(lists.ToList());
}
Upvotes: 1