Get all groups on n from array of length k - c#

I am looking for the best way to get all possible int arrays of length n from int array of length k, including an option for n-1 items to be null.
for example I have the array with 5 elements (k=5) and I want all combinations of 3 (n=3)
int[] numbers = new int[5] {1, 2, 3, 4, 5};
and the possible sub arrays of length 3:
{1,null,null},{1,null,2},{1,2,null}..... and so on.
What would be the best way to do it?
Matan

You could include null in your numbers array.
This code produces all possible permutations except of {null, null, null}.
var numbers = new int?[]{null, 1, 2, 3, 4, 5};
var result = new List<int?[]>();
foreach (int? x in numbers)
{
foreach (int? y in numbers)
{
foreach (int? z in numbers)
{
if (x == null && y == null && z == null)
continue;
result.Add(new int?[] { x, y, z });
Console.WriteLine("x: {0} - y: {1} - z: {2}", x, y, z);
}
}
}

Related

C# Find all values in an array closest to a given number

given:
int[] myArray = new int[]{-8, -17, 12, 8, 16, -3, 7, 3};
Find all values in array closest to 0.
Currently using another code found on the site but it only tells me 1 value.
int nearest = myArray.Select(p => new {Value = p, Difference = Math.Abs(p - searchValue)}).OrderBy(p => p.Difference).First().Value;
In the current case both -3 and 3 are closest to 0 but since -3 comes first it only outputs -3.
Is there another way to do this where it finds all values instead of just First()?
Just to add to this. If you want to do this using O(n) complexity without sorting then you can do it this way :
public List<int> GetClosestNumbers(int searchVal)
{
int[] myArray = new int[] { -8, -17, 12, 8, 16, -3, 7, 3 };
int minimumDist = int.MaxValue;
List<int> output = new List<int>();
for (int i = 0; i < myArray.Length; i++)
{
var currentDistance = Math.Abs(myArray[i] - searchVal);
if (currentDistance < minimumDist)
{
minimumDist = currentDistance;
output.Clear();
output.Add(myArray[i]);
}
else if (minimumDist == currentDistance)
{
output.Add(myArray[i]);
}
}
return output;
}
Use a grouping on the lowest absolute value
int[] result = myArray
.OrderBy(i => Math.Abs(i - searchValue))
.GroupBy(i => Math.Abs(i - searchValue))
.First()
.ToArray();

How to get first index of Binary Search's results?

I have some problems. I have 2 list such as:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
⇒ True result is: {1, 3, 0}
I would like to get the first index of numbers in secondList that exists in firstList. I used list.BinarySearch() but the result was {2, 3, 0}.
List<int> firstList = new List<int> { 1, 2, 2, 3, 5};
List<int> secondList = new List<int> { 2, 3, 1 };
var output = secondList.Select(item => firstList.IndexOf(item)); // [1 , 3 , 0]
You can replace the IndexOf with a BinarySearch logic, but BinarySearch returns the first matched element index, so you won't get the lowest number, IndexOf does return the lowest matching index.
The problem is that when the list contains duplicate values as in your case, the BinarySearch method will return the index of any of the matching values (non deterministic).
To get the desired result, you could create and use a custom extension method like this:
public static class ListExtensions
{
public static int BinarySearchFirst<T>(this List<T> source, T item, IComparer<T> comparer = null)
{
if (comparer == null) comparer = Comparer<T>.Default;
int index = source.BinarySearch(item, comparer);
while (index > 0 && comparer.Compare(source[index], source[index - 1]) == 0)
index--;
return index;
}
}
Sample usage:
var result = secondList.Select(x => firstList.BinarySearchFirst(x)).ToList();
// { 1, 3, 0 }
C++ has a standard library function for this called lower_bound().
Here's a C# implementation. This is useful if you are searching large collections:
public static int LowerBound<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int left = first;
int right = last;
while (left < right)
{
int mid = left + (right - left) / 2;
var middle = values[mid];
if (middle.CompareTo(target) < 0)
left = mid + 1;
else
right = mid;
}
return left;
}
That doesn't return -1 for elements that it doesn't find, so to fix that we can wrap it like so:
public static int LowerBoundOrMinusOne<T>(IList<T> values, T target, int first, int last)
where T : IComparable<T>
{
int result = LowerBound(values, target, first, last);
if (result >= last || result < first || values[result].CompareTo(target) != 0)
return -1;
return result;
}
Here is how you use it:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1 };
List<int> result = secondList
.Select(value => LowerBoundOrMinusOne(firstList, value, 0, firstList.Count))
.ToList();
Console.WriteLine(string.Join(", ", result));
Of course, this is mainly of benefit to large lists because it has an O(Log2(N)) rather than an O(N) complexity.
Iterate through second array and get index of element in first array:
foreach (int item in secondList)
{
Console.WriteLine(firstList.IndexOf(item));
}
If you have a large firstList and so you have to use BinarySearch try amending it: find out the item (which is not guaranteed to be the leftmost one) by BinarySearch, then move to the left while having read the same item:
List<int> firstList = new List<int> { 1, 2, 2, 3, 5 };
List<int> secondList = new List<int> { 2, 3, 1, 123 };
var result = secondList
.Select(item => firstList.BinarySearch(item))
.Select(index => index < 0 ? -1 : Enumerable
.Range(0, index + 1) // we have to scan [0..index] at the worst case
.Select(i => index - i) // scan in reverse
.TakeWhile(i => firstList[index] == firstList[i]) // take while items are the same
.Last()); // finally, we want the last item
Test
// 1, 3, 0, -1
Console.Write(String.Join(", ", result));

Return elements between two variable indexes in a list

I want to return elements between two variable indexes in a list.
For example, given this list -
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
I want to loop through the list using to variables for index values. Let’s call the index values X and Y.
So if X equals an index value of 0 and Y equals a value of 5, I need to loop through the index 0-5 and return all of the element values. X and Y could later become index values of 5 through 8 for example.
How would I accomplish this?
You can use Enumerable.Skip and Enumerable.Take
var res = list.Skip(noOfElementToSkip).Take(noOfElementsToTake);
To using variable as indexes
var res = list.Skip(x).Take(y-x+1);
Note You need to pass the start element index to Skip and for taking number of elements you need to pass number of element you want in Take parameter minus the start element number, plus one list is zero-based index.
you can use List.GetRange
var result = list.GetRange(X, Y-X+1);
or a simple for loop
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (int i = X; i <= Y; i++)
{
Console.WriteLine(list[i]);
}
or reinventing the wheel the way you want
public static class Extensions
{
public static IEnumerable<T> GetRange<T>(this IList<T> list, int startIndex, int endIndex)
{
for (int i = startIndex; i <= endIndex; i++)
{
yield return list[i];
}
}
}
foreach(var item in list.GetRange(0, 5))
{
Console.WriteLine(item);
}
int x = 0, y = 5;
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
for (; x < y; x++)
{
Console.WriteLine(list[x]);
}
This would work if X is always smaller than Y.
If you don't know which is bigger add this before the loop:
if (x > y)
{
x = x ^ y;
y = y ^ x;
x = x ^ y;
}
Another alternative:
int X = 0, Y = 5;
Enumerable.Range(X, Y - X + 1)
.Select(index => list[index]);
It should do the trick -
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int startindex = 1;
int endIndex = 7;
var subList = list.Skip(startindex).Take(endIndex - startindex-1).ToList();

How to sort a List of integer arrays of varying size?

I've done some extensive searching for this so if this is a duplicate please slaughter me :D
I have a List of byte arrays (List) where the arrays are of varying length. I need to sort the list by the array lengths in ascending order then by the bytes in the array (please see example).
Example:
I want to go from:
{0,1,2}
{0,4}
{0,3,2}
{0,1,3}
{0,2,4,6,1}
{0,1,1}
{0,3,4,5}
to:
{0,4}
{0,1,1}
{0,1,2}
{0,1,3}
{0,3,2}
{0,3,4,5}
{0,2,4,6,1}
It's essentially alphabetical order but with a set of numbers instead of characters (arguably the same thing), any ideas?
The only thing you need to do is implement a IComparer<T> interface and provide that to the sorting algorithm. In this case the algorithm looks like:
public ByteArrayComparer : IComparer<byte[]> {
public int Compare (byte[] ba, byte[] bb) {
int n = ba.Length; //fetch the length of the first array
int ci = n.CompareTo(bb.Length); //compare to the second
if(ci != 0) { //if not equal return the compare result
return ci;
} else { //else elementwise comparer
for(int i = 0; i < n; i++) {
if(ba[i] != bb[i]) { //if not equal element, return compare result
return ba[i].CompareTo(bb[i]);
}
}
return 0; //if all equal, return 0
}
}
}
Next you can use the List<T>.Sort method:
List<byte[]> data = new List<byte[]>();
//add arrays to data
data.Sort(new ByteArrayComparer());
//data is now sorted
The sorting algorithm requires that the comparator is valid, a comparator is valid if it satisfies the three constraints on an ordering relation:
Reflexivity: if an elements is compared with itself, return 0;
Anti-symmetric: If x is smaller than y (return something less than 0), then y is greater than x (something greater than 0);
Transitive: if x is smaller than y and y is smaller than z, then x is smaller than z.
If the comparer doesn't satisfy that relation, the sorting algorithm will fail to sort correctly, simply because your order makes no sense.
Why not simply use LINQ
MyList = MyList.OrderBy(arr=>arr.Length).ThenBy(arr =>arr.Sum()).ToList();
A working example :
List<int[]> a = new List<int[]>();
int[] t1 = { 0, 4 };
int[] t2 = { 0, 1, 2 };
int[] t3 = { 0, 1, 3 };
int[] t4 = { 0, 2, 4, 6, 1 };
int[] t5 = { 0, 1, 1 };
int[] t6 = { 0, 3, 4, 5 };
a.Add(t1);
a.Add(t2);
a.Add(t3);
a.Add(t4);
a.Add(t5);
a.Add(t6);
a = a.OrderBy(arr=>arr.Length).ThenBy(arr =>arr.Sum()).ToList();
foreach (int[] item in a)
{
foreach (int item2 in item)
{
Console.Write(" "+item2);
}
Console.WriteLine();
}
Sample output :
0 4
0 1
0 1 2
0 1 3
0 3 4 5
0 2 4 6 1
And as pointed out this could fail in scenarios like {3 4 5} , {4 5 3}

How can I get the sum (average) value of three lists in C#?

I have three lists which each list represents only 0s and 1s which related to the pixel values of three images.
My question is how can I get the sum (average) of those three lists and represent it in a new list?
here is example of my image1:
List<int> image1 = new List<int>();
int blackColor = 0;
for (int x = 0; x < bmp1.Width; x++)
{
for (int y = 0; y < bmp1.Height; y++)
{
Color color = bmp1.GetPixel(x, y);
if (color.ToArgb() == Color.Black.ToArgb())
{
image1.Add(0);
blackColor++;
}
else
{
image1.Add(1);
}
}
}
Let me makes sure I understand the problem. You have three lists of the same length:
list A: 1, 2, 4, 3
list B: 3, 2, 4, 1
List C: 2, 7, 1, 8
and you wish to get a third list that is the average of each:
List D: 2, 4, 3, 4
Yes?
This is a job for zip join.
var sumOfFirstTwo = list1.Zip(list2, (x, y)=>x + y);
sumOfFirstTwo is now the sequence that is the sum of the first two lists.
var sumOfAllThree = sumOfFirstTwo.Zip(list3, (x, y)=>x + y);
sumOfAllThree is now the sequence that is the sum of all three lists.
var average = sumOfAllThree.Select(x=>x/3).ToList();
Make sense?
This works for an arbitrary number of lists
var firstList = new[] { 1, 2, 3, 1 };
var secondList = new[] { 2, 3, 1, 1 };
var thirdList = new[] { 3, 1, 2, 2 };
var lists = new[] { firstList, secondList, thirdList };
var listLengths = lists.Select(x => x.Count());
if (listLengths.Distinct().Count() != 1)
throw new Exception("Line lengths must be the same");
var lengthOfEachList = listLengths.First();
var averages = new List<double>();
for (var i = 0; i != lengthOfEachList; ++i) {
averages.Add(lists.Average(x => x[i]));
}
The LINQ way would be
var averages = Enumerable.Range(0, lengthOfEachList).Select(x => lists.Average(y => y[x]));

Categories

Resources