How to get all combinations of several List<int> [duplicate] - c#

This question already has answers here:
Combination of List<List<int>>
(9 answers)
Closed 9 years ago.
Differs from sugested solution above in that a list item can only appear once for each row.
This is for a booking system for my spa. Different employees can perform different treatments.
I have a List<List<int>>. These are therapists that can perform the treatment that is booked.
Each list (booking) contain a number of integers like this (these are therapists that can perform the booking):
{1, 3, 6}, //Booking 1
{1, 2, 6}, //Booking 2
{1}, //Booking 3
{2,3} //Booking 4
I'd like to see all possible combinations where the number can only appear in one Place. For the above list the two possible ombinations would be:
6,2,1,3 or
3,6,1,2
That is for the first combination:
Booking 1: Therapist 6
Booking 2: Therapist 2
Booking 3: Therapist 1
Booking 4: Therapist 3
Hope this makes the question a Little bit clearer.

Solve by recursion:
static IEnumerable<List<int>> GetCombinations(IEnumerable<List<int>> lists, IEnumerable<int> selected)
{
if (lists.Any())
{
var remainingLists = lists.Skip(1);
foreach (var item in lists.First().Where(x => !selected.Contains(x)))
foreach (var combo in GetCombinations(remainingLists, selected.Concat(new int[] { item })))
yield return combo;
}
else
{
yield return selected.ToList();
}
}
static void Main(string[] args)
{
List<List<int>> lists = new List<List<int>>
{
new List<int> { 1, 3, 6 },
new List<int> { 1, 2, 6 },
new List<int> { 1 },
new List<int> { 2, 3 }
};
var combos = GetCombinations(lists, new List<int>()).Distinct();
foreach (var combo in combos)
Console.WriteLine("{ " + string.Join(", ", combo.Select(x => x.ToString())) + " }");
return;
}
Output:
{ 3, 6, 1, 2 }
{ 6, 2, 1, 3 }

This solution is far from efficient:
private static void Main()
{
List<List<int>> list = new List<List<int>>
{
new List<int>() {1, 3, 6}, //Booking 1
new List<int>() {1, 2, 6}, //Booking 2
new List<int>() {1}, //Booking 3
new List<int>() {2, 3}
};
List<int[]> solutions = new List<int[]>();
int[] solution = new int[list.Count];
Solve(list, solutions, solution);
}
private static void Solve(List<List<int>> list, List<int[]> solutions, int[] solution)
{
if (solution.All(i => i != 0) && !solutions.Any(s => s.SequenceEqual(solution)))
solutions.Add(solution);
for (int i = 0; i < list.Count; i++)
{
if (solution[i] != 0)
continue; // a caller up the hierarchy set this index to be a number
for (int j = 0; j < list[i].Count; j++)
{
if (solution.Contains(list[i][j]))
continue;
var solutionCopy = solution.ToArray();
solutionCopy[i] = list[i][j];
Solve(list, solutions, solutionCopy);
}
}
}
It sounds like this can be solved more efficiently with Dynamic programming, but it's been a while since I took the relevant course.

A simple way to look at this problem would be to choose from all combinations of the list of values, where every value in the combination is unique.
First figure out what all the combinations of values are.
public static IEnumerable<IList<T>> Combinations<T>(IEnumerable<IList<T>> collections)
{
if (collections.Count() == 1)
{
foreach (var item in collections.Single())
yield return new List<T> { item };
}
else if (collections.Count() > 1)
{
foreach (var item in collections.First())
foreach (var tail in Combinations(collections.Skip(1)))
yield return new[] { item }.Concat(tail).ToList();
}
}
Then you need a way to determine if all the values are unique. A simple way to figure that out would be to check if the count of distinct values equals the count of all values.
public static bool AllUnique<T>(IEnumerable<T> collection)
{
return collection.Distinct().Count() == collection.Count();
}
Once you have all that, put it all together.
var collections = new[]
{
new List<int> { 1, 3, 6 },
new List<int> { 1, 2, 6 },
new List<int> { 1 },
new List<int> { 2, 3 },
};
var results =
from combination in Combinations(collections)
where AllUnique(combination)
select combination;
// results:
// 3,6,1,2
// 6,2,1,3

Related

Most efficient way to distribute non unique elements across multiple lists

Suppose that I have a list of integer or whatever
List<int> motherlist = { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 }
Console.WriteLine(children.Count); // 10
I would like to find all duplicates and not remove them from the list but to distribute them across other lists so the final count of all childrens should be the same as motherlist:
List<List<int>> children = { { 1, 2, 5, 7, 6 }, { 1, 2 }, { 1, 2 }, { 2 }}
Console.WriteLine(children.Sum(l => l.Count())); // 10 same as mother
I tried so far a brute force approach by looping through all elements of mother, comparing the elements with all other elements and to check for duplicates, If duplicate found I add it to a list of buckets (List of Lists) and so forth until the last elements.
But the brute force approach takes 7 CPU seconds for only a mother list of 300 items.
I imagine that if I had 1000 items this would take forever.
Is there a faster way to do this in C# .NET ?
I suggest grouping duplicates and then loop taking into account size of the groups:
public static IEnumerable<List<T>> MyDo<T>(IEnumerable<T> source,
IEqualityComparer<T> comparer = null) {
if (null == source)
throw new ArgumentNullException(nameof(source));
var groups = new Dictionary<T, List<T>>(comparer ?? EqualityComparer<T>.Default);
int maxLength = 0;
foreach (T item in source) {
if (!groups.TryGetValue(item, out var list))
groups.Add(item, list = new List<T>());
list.Add(item);
maxLength = Math.Max(maxLength, list.Count);
}
for (int i = 0; i < maxLength; ++i) {
List<T> result = new List<T>();
foreach (var value in groups.Values)
if (i < value.Count)
result.Add(value[i]);
yield return result;
}
}
Demo:
int[] source = new int[] { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 };
var result = MyDo(source).ToList();
string report = string.Join(Environment.NewLine, result
.Select(line => $"[{string.Join(", ", line)}]"));
Console.Write(report);
Outcome:
[1, 2, 5, 7, 6]
[1, 2]
[1, 2]
[2]
Stress Demo:
Random random = new Random(1234); // seed, the results to be reproducible
// We don't want 1000 items be forever; let's try 1_000_000 items
int[] source = Enumerable
.Range(1, 1_000_000)
.Select(x => random.Next(1, 1000))
.ToArray();
Stopwatch sw = new Stopwatch();
sw.Start();
var result = MyDo(source).ToList();
sw.Stop();
Console.WriteLine($"Time: {sw.ElapsedMilliseconds} ms");
Outcome: (may vary from workstation to workstation)
Time: 50 ms
I would GroupBy the elements of the list, and then use the count of elements to know the number of sublists an element has to be added in
List<int> motherlist = new List<int> { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 };
var childrens = motherlist.GroupBy(x => x).OrderByDescending(x => x.Count());
var result = new List<List<int>>();
foreach (var children in childrens)
{
for (var i = 0; i < children.Count(); i++)
{
if (result.Count() <= i) result.Add(new List<int>());
result[i].Add(children.Key);
}
}
Console.WriteLine("{");
foreach (var res in result)
{
Console.WriteLine($"\t{{ { string.Join(", ", res) } }}");
}
Console.WriteLine("}");
This outputs :
{
{ 2, 1, 5, 7, 6 }
{ 2, 1 }
{ 2, 1 }
{ 2 }
}
Just a quick shot, but it seems to work quite well...
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
List<int> motherlist = new List<int> { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 };
var rnd = new Random(1);
for (int i = 0; i < 1000; i++)
{
motherlist.Add(rnd.Next(1, 200));
}
var resultLists = new List<IEnumerable<int>>();
while (motherlist.Any())
{
var subList = motherlist.Distinct().OrderBy(x => x).ToList();
subList.ForEach(x => motherlist.Remove(x));
resultLists.Add(subList);
}
}
}
}
You can use a Dictionary<int, int> to keep track of the number of occurrences of each element and build the child lists in a single iteration with O(n) time complexity(most of the time) and without any LINQ:
var motherlist = new List<int>() { 1, 1, 2, 5, 7, 2, 2, 2, 6, 1 };
var counts = new Dictionary<int, int>();
var children = new List<List<int>>();
foreach(var element in motherlist)
{
counts.TryGetValue(element, out int count);
counts[element] = ++count;
if (children.Count < count)
{
children.Add(new List<int>() { element });
}
else
{
children[count - 1].Add(element);
}
}
OUTPUT
{ 1, 2, 5, 7, 6 }
{ 1, 2 }
{ 2, 1 }
{ 2 }

c# How to set the maximum number when do the find all possible combinations of numbers to reach a given sum

Im new to c# then my supervisor ask me to find all possible combination of given set of numbers and I must set the maximum for the combinations. The combinations I already get but for set the maximum number can't be done.The maximum number is for the combinations. From my image it have 5,4 and 3 row that is all the possible combinations. but I just want to set only output that have 3 row only will be display. I have tried many way but still can't get it. Sorry for my bad english.
Here are the code.
class Program
{
static void Main(string[] args)
{
string input;
decimal goal;
decimal element;
int max = 2;
do
{
Console.WriteLine("Please enter the target:");
input = Console.ReadLine();
}
while (!decimal.TryParse(input, out goal));
Console.WriteLine("Please enter the numbers (separat`enter code here`ed by spaces)");
input = Console.ReadLine();
string[] elementsText = input.Split(' ');
List<decimal> elementsList = new List<decimal>();
foreach (string elementText in elementsText)
{
if (decimal.TryParse(elementText, out element))
{
elementsList.Add(element);
}
}
Solver solver = new Solver();
List<List<decimal>> results = solver.Solve(goal, elementsList.ToArray());
//foreach (List<decimal> result in results)
//{
// foreach (decimal value in result)
// {
// Console.Write("{0}\t", value);
// }
// Console.WriteLine();
//}
for (int i = 0; i <= results.Count; i++)
{
int x = results.SelectMany(list => list).Distinct().Count();
if (x <= max)
{
for (int j = 0; j <= max; j++)
{
Console.Write("{0}\t", results[i][j]);
}
Console.WriteLine();
}
}
Console.ReadLine();
}
}
here is the ouput
From the comments in the question and other answers, it seems to me that the OP already knows how to calculate all the combinations whose sum is a target number (that's probably what the Solver in the question does). What I think he wants is to get the combination with the least amount of numbers.
I have a couple of solutions, since I'm not really sure what you want:
1) If you want all the combinations with the least of amount of numbers, do this:
public static void Main()
{
// Here I have hard-coded all the combinations,
// but in real life you would calculate them.
// Probably using your `Solver` or any of the other answers in this page.
var combinations = new List<List<decimal>>{
new List<decimal>{ 1, 2, 3, 4, 5 },
new List<decimal>{ 1, 2, 5, 7 },
new List<decimal>{ 1, 3, 4, 7 },
new List<decimal>{ 1, 3, 5, 6 },
new List<decimal>{ 2, 3, 4, 6 },
new List<decimal>{ 2, 6, 7 },
new List<decimal>{ 3, 5, 7 },
new List<decimal>{ 4, 5, 6 }
};
// Filter the list above to keep only the lists
// that have the least amount of numbers.
var filteredCombinations = LeastNumbers(combinations);
foreach (var combination in filteredCombinations)
{
Console.WriteLine(string.Join("\t", combination));
}
}
public static List<List<decimal>> LeastNumbers(List<List<decimal>> combinations)
{
// First get the count for each combination, then get the minimum of those.
int smallestLength = combinations.Select(l => l.Count).Min();
// Second, only keep those combinations which have a count equals to the value calculated above.
return combinations.Where(l => l.Count == smallestLength).ToList();
}
Output:
2 6 7
3 5 7
4 5 6
2) If you only want one of the combinations with the least amount of numbers, do this instead:
public static void Main()
{
// Here I have hard-coded all the combinations,
// but in real life you would calculate them.
// Probably using your `Solver` or any of the answers in this page.
var combinations = new List<List<decimal>>{
new List<decimal>{ 1, 2, 3, 4, 5 },
new List<decimal>{ 1, 2, 5, 7 },
new List<decimal>{ 1, 3, 4, 7 },
new List<decimal>{ 1, 3, 5, 6 },
new List<decimal>{ 2, 3, 4, 6 },
new List<decimal>{ 2, 6, 7 },
new List<decimal>{ 3, 5, 7 },
new List<decimal>{ 4, 5, 6 }
};
// Filter the list above to keep only the first list
// that has the least amount of numbers.
var filteredCombination = LeastNumbers(combinations);
Console.WriteLine(string.Join("\t", filteredCombination));
}
public static List<decimal> LeastNumbers(List<List<decimal>> combinations)
{
// First get the count for each combination,
// then get the minimum of those.
int smallestLength = combinations.Select(l => l.Count).Min();
// Second, get only one of the combinations that have a count
// equals to the value calculated above.
return combinations.First(l => l.Count == smallestLength);
}
Output:
2 6 7
3) The OP also mentioned a max value of 3. So, if you know that number before-hand, you can do this:
public static void Main()
{
// Here I have hard-coded all the combinations,
// but in real life you would calculate them.
// Probably using your `Solver` or any of the answers in this page.
var combinations = new List<List<decimal>>{
new List<decimal>{ 1, 2, 3, 4, 5 },
new List<decimal>{ 1, 2, 5, 7 },
new List<decimal>{ 1, 3, 4, 7 },
new List<decimal>{ 1, 3, 5, 6 },
new List<decimal>{ 2, 3, 4, 6 },
new List<decimal>{ 2, 6, 7 },
new List<decimal>{ 3, 5, 7 },
new List<decimal>{ 4, 5, 6 }
};
// This must be known before hand.
// That's why I think my first solution is more usefull.
int max = 3;
// Filter the list above to keep only the lists
// that have a count less or equal to a predetermined maximum.
var filteredCombinations = FilterByMaxLength(combinations, max);
foreach (var combination in filteredCombinations)
{
Console.WriteLine(string.Join("\t", combination));
}
}
public static List<List<decimal>> FilterByMaxLength(List<List<decimal>> combinations, int max)
{
return combinations.Where(l => l.Count <= max).ToList();
}
2 6 7
3 5 7
4 5 6
Note: In a real scenario, you would also want to do some checking in those functions, like checking for null or empty lists.
Here is my try, you can tweak this depending on what you want:
using System.Collections.Generic;
using System.Linq;
private static void GetMaxPermutation(int max)
{
var numbers = new[] { 1, 2, 4, 6, 7 };
var results = new List<IEnumerable<int>>();
for (int i = 1; i <= numbers.Length; i++)
{
results.AddRange(GetPermutations(numbers, i));
}
Console.WriteLine("Result: " + string.Join(" ", results.Select(x => new { Target = x, Sum = x.Sum() }).Where(x => x.Sum <= max).OrderByDescending(x => x.Sum).FirstOrDefault().Target));
}
private static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> items, int count)
{
int i = 0;
foreach (var item in items)
{
if (count == 1)
yield return new T[] { item };
else
{
foreach (var result in GetPermutations(items.Skip(i + 1), count - 1))
yield return new T[] { item }.Concat(result);
}
++i;
}
}
I got this permutations method from here
Hard to find what you're trying to do, is something like this
List<string> numbers = new List<string>(){"1","2","3","4","5"};
List<string> possibleCombination = GetCombination(numbers, new List<string>(), "");
Console.Write(string.Join(", ",possibleCombination.Distinct().OrderBy(itm => itm)));
The method
static List<string> GetCombination(List<string> list, List<string> combinations, string sumNum, bool addNumberToResult = false)
{
if (list.Count == 0) {
return combinations;
}
string tmp;
for (int i = 0; i <= list.Count - 1; i++) {
tmp = string.Concat(sumNum , list[i]);
if(addNumberToResult){
combinations.Add(tmp);
}
List<string> tmp_list = new List<string>(list);
tmp_list.RemoveAt(i);
GetCombination(tmp_list,combinations,tmp, true);
}
return combinations;
}
C# Fiddle can help you?

Merge multiple lists with variable length "popping" elements from each

I'd like to sort multiple lists (variable number of them) into single list, but keeping the specific order. For example:
List A: { 1,2,3,4,5 }
List B: { 6,7,8 }
List C: { 9,10,11,12 }
Result List: { 1,6,9,2,7,10,3,8,11,4,12,5 }
The only idea I got was to remove the first element from each list and put it into resulting set (and repeat until all lists are empty), but maybe there is a better way that doesn't require to create copy of each list and doesn't affect the original lists as well?
I suggest using IEnumerator<T> to enumerate lists while they have items:
private static IEnumerable<T> Merge<T>(params IEnumerable<T>[] sources) {
List<IEnumerator<T>> enums = sources
.Select(source => source.GetEnumerator())
.ToList();
try {
while (enums.Any()) {
for (int i = 0; i < enums.Count;)
if (enums[i].MoveNext()) {
yield return enums[i].Current;
i += 1;
}
else {
// exhausted, let's remove enumerator
enums[i].Dispose();
enums.RemoveAt(i);
}
}
}
finally {
foreach (var en in enums)
en.Dispose();
}
}
Test
List<int> A = new List<int>() { 1, 2, 3, 4, 5 };
List<int> B = new List<int>() { 6, 7, 8 };
List<int> C = new List<int>() { 9, 10, 11, 12 };
var result = Merge(A, B, C)
.ToList();
Console.Write(string.Join(", ", result));
The outcome is
1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5
For more flexible use
public static string MergeArrays(params IList<int>[] items)
{
var result = new List<int>();
for (var i = 0; i < items.Max(x => x.Count); i++)
result.AddRange(from rowList in items where rowList.Count > i select rowList[i]);
return string.Join(",", result);
}
.
var a = new List<int>() { 1, 2, 3, 4, 5 };
var b = new List<int>() { 6, 7, 8 };
var c = new List<int>() { 9, 10, 11, 12, 0, 2, 1 };
var r = MergeArrays(a, b, c);
There is no sense in over complicating this in my opinion, why not use a simple for loop to accomplish what you need?
List<int> list1 = new List<int> { 1, 2, 3, 4, 5 };
List<int> list2 = new List<int> { 6, 7, 8 };
List<int> list3 = new List<int> { 9, 10, 11, 12 };
List<int> resultList = new List<int>();
for (int i = 0; i < list1.Count || i < list2.Count || i < list3.Count; i++)
{
if (i < list1.Count) resultList.Add(list1[i]);
if (i < list2.Count) resultList.Add(list2[i]);
if (i < list3.Count) resultList.Add(list3[i]);
}
Result: 1,6,9,2,7,10,3,8,11,4,12,5
Here's a fairly simple way. It was fun to write up anyway.
No, it isn't the best, but it works and you could expand it to suit your needs of using a List<List<int>> very easily.
//Using arrays for simplicity, you get the idea.
int[] A = { 1, 2, 3, 4, 5 };
int[] B = { 6, 7, 8 };
int[] C = { 9, 10, 11, 12 };
List<int> ResultSet = new List<int>();
//Determine this somehow. I'm doing this for simplicity.
int longest = 5;
for (int i = 0; i < longest; i++)
{
if (i < A.Length)
ResultSet.Add(A[i]);
if (i < B.Length)
ResultSet.Add(B[i]);
if (i < C.Length)
ResultSet.Add(C[i]);
}
//ResultSet contains: { 1, 6, 9, 2, 7, 10, 3, 8, 11, 4, 12, 5 }
As you can see, just pop this out into a method and loop through your lists of lists, properly determining the max length of all lists.
I'd go with:
static void Main(string[] args)
{
var a = new List<int>() { 1, 2, 3, 4, 5 };
var b = new List<int>() { 6, 7, 8 };
var c = new List<int>() { 9, 10, 11, 12 };
var abc = XYZ<int>(new[] { a, b, c }).ToList();
}
static IEnumerable<T> XYZ<T>(IEnumerable<IList<T>> lists)
{
if (lists == null)
throw new ArgumentNullException();
var finished = false;
for (int index = 0; !finished; index++)
{
finished = true;
foreach (var list in lists)
if (list.Count > index) // list != null (prior checking for count)
{
finished = false;
yield return list[index];
}
}
}
I had to use use IList to have indexer and Count. It doesn't creates anything (no enumerators, no lists, etc.), purely yield return.
For your problem I create static method, which can merge any collections as you want:
public static class CollectionsHandling
{
/// <summary>
/// Merge collections to one by index
/// </summary>
/// <typeparam name="T">Type of collection elements</typeparam>
/// <param name="collections">Merging Collections</param>
/// <returns>New collection {firsts items, second items...}</returns>
public static IEnumerable<T> Merge<T>(params IEnumerable<T>[] collections)
{
// Max length of sent collections
var maxLength = 0;
// Enumerators of all collections
var enumerators = new List<IEnumerator<T>>();
foreach (var item in collections)
{
maxLength = Math.Max(item.Count(), maxLength);
if(collections.Any())
enumerators.Add(item.GetEnumerator());
}
// Set enumerators to first item
enumerators.ForEach(e => e.MoveNext());
var result = new List<T>();
for (int i = 0; i < maxLength; i++)
{
// Add elements to result collection
enumerators.ForEach(e => result.Add(e.Current));
// Remobve enumerators, in which no longer have elements
enumerators = enumerators.Where(e => e.MoveNext()).ToList();
}
return result;
}
}
Example of using:
static void Main(string[] args)
{
var a = new List<int> { 1, 2, 3, 4, 5 };
var b = new List<int> { 6, 7, 8 };
var c = new List<int> { 9, 10, 11, 12 };
var result= CollectionsHandling.Merge(a, b, c);
}
When you understand how it works, it will be possible to reduce the method of smaller.
Shortest and probably slowest solution
int[] A = { 1, 2, 3, 4, 5 };
int[] B = { 6, 7, 8 };
int[] C = { 9, 10, 11, 12 };
var arrs = new[] { A, B, C };
var merged = Enumerable.Range(0, arrs.Max(a => a.Length))
.Select(x => arrs.Where(a=>a.Length>x).Select(a=>a[x]))
.SelectMany(x=>x)
.ToArray();
upd.
Another way to solve - I just refactored #Sinatr answer.
static IEnumerable<T> XYZ<T>(IEnumerable<IList<T>> lists)
{
if (lists == null)
throw new ArgumentNullException();
var index = 0;
while (lists.Any(l => l.Count > index))
{
foreach (var list in lists)
if (list.Count > index)
yield return list[index];
index++;
}
}

How to find complex permutations based on and/or rules of lists of numbers, C#/Linq

The current problem is that the code works, but it gets exponentially slower as more combinations are passed in. (The calculation takes > 5 seconds after 15 combinations are passed in.) I need to be able to pass in up to 100 combinations and still get a result back that takes less than 2 seconds.
I'm betting that a Linq query could solve this?
What I want to achieve:
{1, 2, 3} + {1, 5, 26, 40} = 12 combinations:
[1,1]
[1,5]
[1,26]
[1,40]
[2,1]
[2,5]
[2,26]
[2,40]
[3,1]
[3,5]
[3,26]
[3,40]
However, this example above only includes 2 combination sets. I should be able to pass in any number of combination sets.
The closest thing that looks like it is similar to what I want as an end result, due to being fast and efficient, is a linq query that handles most or all of the logic within it. Example: Getting all possible combinations from a list of numbers
public IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Example of working code:
[Test]
public void StackOverflowExample_Simple()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 1, 5, 26, 40 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2 };
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(12, results.Count());
StringBuilder sb = new StringBuilder();
foreach (var result in results)
{
foreach (var number in result.OrderBy(x => x))
{
sb.Append(number + ",");
}
sb.Append("|");
}
string finalResult = sb.ToString().Replace(",|", "|");
Assert.AreEqual(finalResult, "1,1|1,5|1,26|1,40|1,2|2,5|2,26|2,40|1,3|3,5|3,26|3,40|");
}
[Test]
public void StackOverflowExample_TakesALongTime()
{
var list1 = new List<int>() { 1, 2, 3 };
var list2 = new List<int>() { 4, 5 };
var list3 = new List<int>() { 1, 6 };
var list4 = new List<int>() { 2, 5 };
var list5 = new List<int>() { 1, 3, 55, 56 };
var list6 = new List<int>() { 3, 4, 7, 8, 9 };
var myListsOfNumberCombinations = new List<List<int>>() { list1, list2, list3, list4, list5, list1, list1, list1, list3, list4, list4, list5, list6, list6, list2 };
DateTime startTime = DateTime.Now;
var results = GetAllPossibleCombinations(myListsOfNumberCombinations);
Assert.AreEqual(4147200, results.Count());
var duration = DateTime.Now.Subtract(startTime).TotalSeconds;
//duration = about 4 or 5 seconds
Assert.Less(duration, 10); //easy place to put a breakpoint
}
public IEnumerable<IEnumerable<int>> GetAllPossibleCombinations(List<List<int>> combinationSets)
{
List<List<int>> returnList = new List<List<int>>();
_RecursiveGetMoreCombinations(
ref returnList,
new List<int>(),
combinationSets,
0);
return returnList;
}
private void _RecursiveGetMoreCombinations(
ref List<List<int>> returnList,
List<int> appendedList,
List<List<int>> combinationSets,
int index)
{
var combinationSet = combinationSets[index];
foreach (var number in combinationSet)
{
List<int> newList = appendedList.AsEnumerable().ToList();
newList.Add(number);
if (combinationSets.Count() == index + 1)
{
returnList.Add(newList);
}
else
{
_RecursiveGetMoreCombinations(
ref returnList,
newList,
combinationSets,
index + 1);
}
}
}
Can you not just do permutations of the first and third sets (the OR sets) and then place '45' (the AND set), or whatever the static numbers are, in between those numbers?
You don't need to include 4 and 5 (in this example) in the permutation logic if they are always going to be present.

Linq compare 2 lists of arrays

I would like to compare 2 lists of arrays. Let's take for instance this example:
List<int[]> list1 = new List<int[]>() { new int[4] { 1, 2, 3, 4 }, new int[4] { 1, 2, 3, 5 } };
List<int[]> list2 = new List<int[]>() { new int[2] { 1, 2 }, new int[2] { 3, 4 }, new int[2] { 3, 5 } };
I would like to know for each element in list1 to calculate for every element in list 2 how many common elements they have.
Ex. 1,2,3,4 compared with 1,2 will result to 2 matching elements.
1,2,3,4 compared with 3,5 will result to 1 matching element.
This is not duplicated as I don't wish to compare regular lists. I wish to see for each record in list1 how many items from list2 contain how many common items.
List<int[]> list1 = new List<int[]>() { new int[4] { 1, 2, 3, 4 }, new int[4] { 1, 2, 3, 5 } };
List<int[]> list2 = new List<int[]>() { new int[2] { 1, 2 }, new int[2] { 3, 4 }, new int[2] { 3, 5 } };
var results = list1.Select(x => list2.Select(y => y.Intersect(x).Count()).ToList()).ToList();
Result contains following data: [ [ 2, 2, 1 ], [ 2, 1, 2 ] ]
You can use Enumerable.Intersect to find out common items of first found in second list.
var commonList = list1.Intersect(list2);
The intersection of two sets A and B is defined as the set that
contains all the elements of A that also appear in B, but no other
elements
Edit Since you have array as element of list you have to go through each list item.
List<int[]> list1 = new List<int[]>() { new int[4] { 1, 2, 3, 4 }, new int[4] { 1, 2, 3, 5 } };
List<int[]> list2 = new List<int[]>() { new int[2] { 1, 2 }, new int[2] { 3, 4 }, new int[2] { 3, 5 } };
List<int[]> list3 = new List<int[]>();
for (int i = 0; i < list1.Count; i++)
{
list3.Add(list1[i].Intersect(list2[i]).ToArray());
}
You'd do something like this:
var results =
from x in list1.Select((array, index) => new { array, index })
from y in list2.Select((array, index) => new { array, index })
select new
{
list1_index = x.index,
list2_index = y.index,
count = x.array.Intersect(y.array).Count()
};
foreach(var r in results)
{
Console.WriteLine("({0}, {1}) have {2} item(s) in common.", r.list1_index, r.list2_index, r.count);
}
// (0, 0) have 2 item(s) in common.
// (0, 1) have 2 item(s) in common.
// (0, 2) have 1 item(s) in common.
// (1, 0) have 2 item(s) in common.
// (1, 1) have 1 item(s) in common.
// (1, 2) have 2 item(s) in common.
var commons = list1.Select(x => list2.Select(x.Intersect).ToArray()).ToArray();
Console.WriteLine(commons[0][0]); // Commons between list1[0] and list2[0]
Console.WriteLine(commons[0][1]); // Commons between list1[0] and list2[1]
Console.WriteLine(commons[3][0]); // Commons between list1[3] and list2[0]
Console.WriteLine(commons[3][0].Length); // Number of commons between [3] and [0]
Accourding to ur requirement, I think in C# there isnt such inbuild function in list which do exactly what you want but following function return exactly what you required in resultList. Hope this help you.
private List<int> MatchList()
{
List<int[]> list1 = new List<int[]>() { new int[4] { 1, 2, 3, 4 }, new int[4] { 1, 2, 3, 5 } };
List<int[]> list2 = new List<int[]>() { new int[2] { 1, 2 }, new int[2] { 3, 4 }, new int[2] { 3, 5 } };
List<int> resultList = new List<int>();
for (int i = 0; i < list1.Count; i++)
{
for (int j = 0; j < list2.Count; j++)
{
if (i == j)
{
int result = 0;
foreach (int list1Element in list1[i])
{
foreach (int list2Element in list2[j])
{
if (list1Element == list2Element)
{
result +=1;
}
}
}
resultList.Add(result);
}
}
}
return resultList;
}

Categories

Resources