Getting all possible combinations from a list of numbers - c#

I'm looking for an efficient way to achieve this:
you have a list of numbers 1.....n (typically: 1..5 or 1..7 or so - reasonably small, but can vary from case to case)
you need all combinations of all lengths for those numbers, e.g. all combinations of just one number ({1}, {2}, .... {n}), then all combinations of two distinct numbers ({1,2}, {1,3}, {1,4} ..... {n-1, n} ), then all combinations fo three of those numbers ({1,2,3}, {1,2,4}) and so forth
Basically, within the group, the order is irrelevant, so {1,2,3} is equivalent to {1,3,2} - it's just a matter of getting all groups of x numbers from that list
Seems like there ought to be a simple algorithm for this - but I have searched in vain so far. Most combinatorics and permutation algorithms seems to a) take order into account (e.g. 123 is not equal to 132), and they always seems to operate on a single string of characters or numbers....
Anyone have a great, nice'n'quick algorithm up their sleeve??
Thanks!

Not my code, but you're looking for the powerset. Google gave me this solution, which seems t work:
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];
}
Source: http://rosettacode.org/wiki/Power_set#C.23

Just increment a binary number and take the elements corresponding to bits that are set.
For instance, 00101101 would mean take the elements at indexes 0, 2, 3, and 5. Since your list is simply 1..n, the element is simply the index + 1.
This will generate in-order permutations. In other words, only {1, 2, 3} will be generated. Not {1, 3, 2} or {2, 1, 3} or {2, 3, 1}, etc.

This is something I have written in the past to accomplish such a task.
List<T[]> CreateSubsets<T>(T[] originalArray)
{
List<T[]> subsets = new List<T[]>();
for (int i = 0; i < originalArray.Length; i++)
{
int subsetCount = subsets.Count;
subsets.Add(new T[] { originalArray[i] });
for (int j = 0; j < subsetCount; j++)
{
T[] newSubset = new T[subsets[j].Length + 1];
subsets[j].CopyTo(newSubset, 0);
newSubset[newSubset.Length - 1] = originalArray[i];
subsets.Add(newSubset);
}
}
return subsets;
}
It's generic, so it will work for ints, longs, strings, Foos, etc.

Related

How to generate powersets with a maximum size in C#?

I am trying to generate all powersets from a given list within a limit of given maximum size. I've found some great answers for how to generate powersets in general and admire the solution using bitmaps found here All Possible Combinations of a list of Values or here Computing Powersets in C#.
Is there a way to generate sets with a maximum size of 'maxSize' numbers in one set? E.g. my input is {1, 2, 3, 4, 5, 6}, but I only want results with 3 or less items. Is it possible to do within the one command? I have found a solution where I iterate over all items of the result, but this is quite inefficient for large inputs with smaller maxSize.
It's easy with recursion:
static public IEnumerable<List<int>> FindAllCombos(List<int> list, int maxSize, int minIndex = 0)
{
yield return new List<int>();
if (maxSize > 0)
for (int i = minIndex; i < list.Count; i++)
foreach (var set in FindAllCombos(list, maxSize - 1, i + 1))
{
set.Add(list[i]);
yield return set;
}
}
Note that the elements of the output sets will here be in the reverse order.

Finding all possible combinations with repitition of selected items allowed

I have a List of objects, The number of these objects is dynamic.I need to find all possible combinations of these objects.
I currently am at a stage where I take a list of objects , and return all possible combinations without repitition using the following code :
static void Main(string[] args)
{
//Say, inputList contains randomObject1,randomObject2 and randomObject3
List<List<RandomObject>> AllCombos = ItemCombinations(inputList);
}
//maxComboCount denotes the maximum number of elements that can be in the combination
public static List<List<T>> ItemCombinations<T>(List<T> inputList, int maxComboCount)
{
int nonEmptyCombinations = (int)Math.Pow(2, inputList.Count) - 1;
List<List<T>> listOfCombinations = new List<List<T>>();
for (int i = 1; i <= nonEmptyCombinations; i++)
{
List<T> thisCombination = new List<T>();
for (int j = 0; j < inputList.Count; j++)
{
if ((i >> j) % 2 != 0)
{
thisCombination.Add(inputList[j]);
}
}
if (thisCombination.Count <= maxComboCount)
{
listOfCombinations.Add(thisCombination);
}
}
return listOfCombinations;
}
How do I get all the other combinations where the items are repeated , the maxComboCount will always be there otherwise my required scenario might get stuck in an infinite loop (Correct me if I'm wrong).
E.g. InputList : {r1,r2,r3}
Current stage : {r1},{r2},{r3},{r1,r2},{r2,r3},{r3,r1},{r1,r2,r3}
Wanted stage (given maxComboCount constraint = 4) : {r1},{r2},{r3},{r1,r1},{r1,r2},{r1,r3},{r2,r2},{r2,r3},{r3,r3} {r1,r1,r1}, {r1,r1,r2} ,{r1,r1,r3},{r1,r2,r3} and so on...
One thing I tried was,
I iterated till maxBaseCardCount and added the inputList at each iteration to another tempList, I then passed this tempList as a parameter in the ItemCombinations method.
//The loop will be constrained by the maximum number of objects allowed
for (int i = 0; i < maxComboCount; i++)
{
tempList.AddRange(inputList);
}
List<List<RandomObject>> AllCombos = ItemCombinations(tempList);
This was supposed to be a fast and dirty work around, and does give me my required output (with a lot of duplicate values) but I am not very sure about how much it can hold before breaking. So, any approach more reliable than my one will be much appreciated.
Edit
I am adding an explanation of the problem, please let me know if any other simplification is required
InputList : It is a list of objects from which combinations are to be made
ItemCombinations: This function returns all combinations from a given list without repitition (not what I want)
For an inputList = {1,2}, ItemCombination returns : empty, {1},{2},{1,2} i.e. all 2^n unique combinations from any given list of length n
Now, I want this to combine the items with repetitions allowed and the length of combinations dynamic.
Example :
E.g. InputList : {r1,r2,r3}
ItemCombination function originally returns : {r1},{r2},{r3},{r1,r2},{r2,r3},{r3,r1},{r1,r2,r3}
Now, what I want is , all the combinations that can be made, if there was no limit on how many times each object could be used
What I want (given maxComboCount constraint = 4) : {r1},{r2},{r3},{r1,r1},{r1,r2},{r1,r3},{r2,r2},{r2,r3},{r3,r3} {r1,r1,r1}, {r1,r1,r2} ,{r1,r1,r3},{r1,r2,r3} and so on...
The maxComboCount constraint makes sure that the no list with size>4 is returned
Basically , I want a combination of k objects chosen from n objects, where k can range from 1 to x (any number)
You want to find the combinations of drawing up to m items from a pool of n items with repetition. Order doesn't matter in the sets of items, so that {1, 2, 2} and {2, 2, 1} are equivalent; only one of them should be added. (Ideally, this is the one where the items are in ascending order.)
Suppose you have a pool of three items and want to create sets of up to two items. Add the empty set to your results:
{}
Create sets of one item by iterating the sets with no items and the item pool and adding items:
{} + {1} = {1}
{} + {2} = {2}
{} + {3} = {3}
Now create sets of two items from the sets with one item, but only add items when they are equal to or larger than the last and largest item in each set:
{1} -> {1, 1}, {1, 2}, {1, 3}
{2} -> {2, 2}, {2, 3}
{3} -> {3, 3}
Now you have a set of T(1) + T(2) + T(3) = 10 items:
{}
{1}, {2}, {3}
{1, 1}, {1, 2}, {1, 3}, {2, 2}, {2, 3}, {3, 3}
(T(n) is the nth triangle number, ¹ ⁄₂·n·(n + 1).)
I don't know C#, but in pseudo-code, your algorithm looks like this:
var m = 3 // max. items
var pool = {1, 2, 3} // item pool
var res = {{}} // results,
// start with empty list
var k = 0 // starting index of subarray
// with one fewer item
while (m--) { // loop m times
var kk = res.length() // current result array length
for (var i = k; i < kk; i++) {
var j0 = 0
if (res[i].length() > 0) { // find index of largest item
j0 = pool.index(res[i].last()) // from the set in pool
}
for (var j = j0; j p in pool { // add new set
res.add(res[i] + {pool[j]})
}
}
k = kold
}
This can also be implemented recursively, where you keep track of the last item index in each level, so that you don't have to search it.

C# How to make recursive function to return the nth most common integer in an array of integers

C# How to make recursive function to return the nth most common integer in an array of integers
I am using c# and I am looking for the most memory efficient way to sort a list of integers by how often they appear in an integer array and then return the nth array element where nth is an integer represent the descending order key of choice (most used integer, 2nd most used integer, 3rd most used integer, etc.
I can do this using linq with something like this...
public static void Main(string[] args)
{
int x = NthMostCommon(new int[] { 5, 4, 3, 2, 1, 5, 4, 3, 2, 5, 4, 3, 5, 4, 5 }, 2);
Console.WriteLine(x);
}
private static int NthMostCommon(int[] a, int k)
{
int result = 0;
var query = a.GroupBy(item => item).OrderByDescending(g => g.Count());
if (query.Count() >= k)
{
result = query.ElementAt(k - 1).Key;
}
return result;
}
This works, but I have been told that this is not the most memory efficient way of getting the desired result when working with larger integer arrays. I cannot see how I can reduce the memory footprint. I have to iterate the entire array, regardless of the size. Yes?
Any ideas?
Thanks in advance.
This article may help you.
http://www.developerfusion.com/article/84468/linq-to-log-files/
the most common integer could be more than 1 integer (see the int array in my code), so I make the function to return int[] instead of just int.
I also have GroupBy which in worst case (identical integer in the input array) could be the same efficient as the previous one. You may also be able to rewrite it.
public static void Main(string[] args)
{
int[] x = NthMostCommon(new int[] { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6 }, 2);
Console.WriteLine(x);
}
private static int[] NthMostCommon(int[] a, int k)
{
var query = GroupAndCount(a)
.GroupBy(x => x.Value)
.ToDictionary(x => x.Key, x => x.Select(n => n.Key))
.OrderByDescending(x => x.Key);
if (query.Count() >= k)
{
return query.ElementAt(k-1).Value.ToArray();
}
return null;
}
public static IEnumerable<KeyValuePair<T, int>> GroupAndCount<T>
(IEnumerable<T> source)
{
Dictionary<T, int> dictionary =
new Dictionary<T, int>();
foreach (T element in source)
{
if (dictionary.ContainsKey(element))
{
dictionary[element]++;
}
else {
dictionary[element] = 1;
}
}
return dictionary;
}
Where k << n and 0 < x < k, where x is an integer, start with a Counting Sort and modify it.
A counting sort takes O(n + k) memory and O(n + k) time.
In computer science, counting sort is an algorithm for sorting a collection of objects according to keys that are small integers; that is, it is an integer sorting algorithm. It operates by counting the number of objects that have each distinct key value, and using arithmetic on those counts to determine the positions of each key value in the output sequence.
Its running time is linear in the number of items and the difference between the maximum and minimum key values, so it is only suitable for direct use in situations where the variation in keys is not significantly greater than the number of items. However, it is often used as a subroutine in another sorting algorithm, radix sort, that can handle larger keys more efficiently.
After the items are sorted according to frequency it's simply a matter of walking the result.
If there is really a "requirement" to be recursive the procedural loop code can be converted into recursive calls, at the expense of stackframes. Using LINQ - which provides various higher-order functions - often trivial eliminates the need for recursion.

Top 5 values from three given arrays

Recently i faced a question in
C#,question is:-
There are three int arrays
Array1={88,65,09,888,87}
Array2={1,49,921,13,33}
Array2={22,44,66,88,110}
Now i have to get array of highest 5 from all these three arrays.What is the most optimized way of doing this in c#?
The way i can think of is take an array of size 15 and add array elements of all three arrays and sort it n get last 5.
An easy way with LINQ:
int[] top5 = array1.Concat(array2).Concat(array3).OrderByDescending(i => i).Take(5).ToArray();
An optimal way:
List<int> highests = new List<int>(); // Keep the current top 5 sorted
// Traverse each array. No need to put them together in an int[][]..it's just for simplicity
foreach (int[] array in new int[][] { array1, array2, array3 }) {
foreach (int i in array) {
int index = highests.BinarySearch(i); // where should i be?
if (highests.Count < 5) { // if not 5 yet, add anyway
if (index < 0) {
highests.Insert(~index, i);
} else { //add (duplicate)
highests.Insert(index, i);
}
}
else if (index < 0) { // not in top-5 yet, add
highests.Insert(~index, i);
highests.RemoveAt(0);
} else if (index > 0) { // already in top-5, add (duplicate)
highests.Insert(index, i);
highests.RemoveAt(0);
}
}
}
Keep a sorted list of the top-5 and traverse each array just once.
You may even check the lowest of the top-5 each time, avoiding the BinarySearch:
List<int> highests = new List<int>();
foreach (int[] array in new int[][] { array1, array2, array3 }) {
foreach (int i in array) {
int index = highests.BinarySearch(i);
if (highests.Count < 5) { // if not 5 yet, add anyway
if (index < 0) {
highests.Insert(~index, i);
} else { //add (duplicate)
highests.Insert(index, i);
}
} else if (highests.First() < i) { // if larger than lowest top-5
if (index < 0) { // not in top-5 yet, add
highests.Insert(~index, i);
highests.RemoveAt(0);
} else { // already in top-5, add (duplicate)
highests.Insert(index, i);
highests.RemoveAt(0);
}
}
}
}
The most optimized way for a fixed K=5 is gong through all arrays five times, picking the highest element not taken so far on each pass. You need to mark the element that you take in order to skip it on subsequent passes. This has the complexity of O(N1+N2+N3) (you go through all N1+N2+N3 elements five times), which is as fast as it can get.
You can combine the arrays using LINQ, sort them, then reverse.
int[] a1 = new int[] { 1, 10, 2, 9 };
int[] a2 = new int[] { 3, 8, 4, 7 };
int[] a3 = new int[] { 2, 9, 8, 4 };
int[] a4 = a1.Concat(a2).Concat(a3).ToArray();
Array.Sort(a4);
Array.Reverse(a4);
for (int i = 0; i < 5; i++)
{
Console.WriteLine(a4[i].ToString());
}
Console.ReadLine();
Prints: 10, 9, 9, 8, 8 from the sample I provided as input for the arrays.
Maybe you could have an array of 5 elements which would be the "max values" array.
Initially fill it with the first 5 values, which in your case would just be the first array. Then loop through the rest of the values. For each value, check it against the 5 max values from least to greatest. If you find the current value from the main list is greater than the value in the max values array, insert it above that element in the array, which would push the last element out. At the end you should have an array of the 5 max values.
For three arrays of length N1,N2,N3, the fastest way should be combining the 3 arrays, and then finding the (N1+N2+N3-4)th order statistic using modified quick sort.
In the resultant array, the elements with indices (N1+N2+N3-5) to the maximum (N1+N2+N3-1) should be your 5 largest. You can also sort them later.
The time complexity of this approach is O(N1+N2+N3) on average.
Here are the two ways for doing this task. The first one is using only basic types. This is the most efficient way, with no extra loop, no extra comparison, and no extra memory consumption. You just pass the index of elements that need to be matched with another one and calculate which is the next index to be matched for each given array.
First Way -
http://www.dotnetbull.com/2013/09/find-max-top-5-number-from-3-sorted-array.html
Second Way -
int[] Array1 = { 09, 65, 87, 89, 888 };
int[] Array2 = { 1, 13, 33, 49, 921 };
int[] Array3 = { 22, 44, 66, 88, 110 };
int [] MergeArr = Array1.Concat(Array2).Concat(Array3).ToArray();
Array.Sort(MergeArr);
int [] Top5Number = MergeArr.Reverse().Take(5).ToArray()
Taken From -
Find max top 5 number from three given sorted array
Short answer: Use a SortedList from Sorted Collection Types in .NET as a min-heap.
Explanation:
From the first array, add 5 elements to this SortedList/min-heap;
Now iterate through all the rest of the elements of arrays:
If an array element is bigger than the smallest element in min-heap then remove the min element and push this array element in the heap;
Else, continue to next array element;
In the end, your min-heap has the 5 biggest elements of all arrays.
Complexity: Takes Log k time to find the minimum when you have a SortedList of k elements. Multiply that by total elements in all arrays because you are going to perform this 'find minimum operation' that many times.
Brings us to overall complexity of O(n * Log k) where n is the total number of elements in all your arrays and k is the number of highest numbers you want.

Delete Duplicate from an Array

I need to delete duplicate entries from an array, but can't use any new data structures and the same array should return only distinct elements. For example, if my array is 1,3,3,3,5,55,67,1 then the result should be 1,3,5,55,67.
I believe I have solved the problem, but I need your opinion on whether it is a good algorithm or if I need to change something.
public void DeleteDuplicate(int[] array)
{
int l = 0;
int newPosition = array.Length -1;
for (int i = 0; i < array.Length; i++)
{
for (int j = i + 1; j < array.Length-l; j++)
{
if (array[i] == array[j])
{
int temp = array[j];
array[j] = array[newPosition];
array[newPosition] = temp;
newPosition--;
l++;
}
}
}
Array.Resize(ref array, array.Length - l);
}
Your code is buggy. Try running it against {1, 1, 1} - I think it will return {1, 1}.
In general, the question whether you have to maintain the relative ordering of the elements. For example, whether it is possible to return {1, 2} for input {2, 1, 2, 1}.
If it is allowed, then the fastest solution will be:
sort input array
run once through it comparing a[i] with a[i+1] and removing duplicates in O(N)'
The total complexity would be O(N*logN), which is better than N^2 you proposed.
If you must preserve the initial ordering, then I am not ready to propose a solution.
Last time I checked C# allowed you to sort 2 arrays by using one for the comparisons and doing the swaps on both.
Here's what you can do:
Create an array indices that stores the numbers 0 to N-1.
Sort array and indices using array as the key.
Find the duplicates and set the indices of duplicates to N+1.
Sort array and indices using indices as key.
Resize the array to the correct size and presto.
This removes duplicates and preserves ordering.

Categories

Resources