Distance between two values - c#

I have a array
int[] Values = new int[] { 5, 43, 45, 25, 16, 89, 65, 36, 62 };
and currently i am calculating the maximum distance between all values 84 = 89 - 5
int MaxDistance = Values.SelectMany((a) => Values.Select((b) => Math.Abs(a - b))).Max();
now I want to calculate the minimum distance 2 = 45 - 43
#ycsun's commment - this doesn't work
int MinDistancee = Values.SelectMany((ia, a) => Values.Select((ib, b) => ib == ia ? int.MaxValue : Math.Abs(a - b))).Min();

Try this instead
int MinDistance = Values.SelectMany(
(a, i) => Values.Skip(i + 1).Select((b) => Math.Abs(a - b))).Min();
This makes sure you don't calculate the difference between numbers at the same index or a set of numbers at different indexes twice. Basically this uses the overload of SelectMany that includes the index, then you just want to do your difference with all the numbers after the current index by using Skip.
It should be noted that a solution using for loops in the form of
for(int i = 0; i < Values.Length - 1; i++)
for(int j = i + 1; j < Values.Length; j++)
would be more performant though.
One caveat here though is if you have negative numbers. Then there will be a difference between the absolute value of a-b versus b-a. In that case you'd want to sort the list first to make sure the difference always has a as the larger number.

Just two simple loops:
int[] Values = new int[] { 5, 43, 45, 25, 16, 89, 65, 36, 62 };
int min = -1;
for (int i = 0; i < Values.Length - 1; ++i)
for (int j = i + 1; j < Values.Length; ++j) { // please, notice j = i + 1
int v = Math.Abs(Values[i] - Values[j]);
if ((min < 0) || (v < min))
min = v;
}
// 2 == 45 - 43
Console.Write(min);

Related

How do I compare two arrays to find common elements (random numbers vs. user input)?

I'm trying to create a lottery number program that accepts 10 guesses from the user between the numbers 1-25. The user guesses are stored in the user array. If the user enters the wrong value (< 1 or > 25) the number will not be stored within the user array. The program stores 10 random numbers in another array. So, two arrays in total.
How to compare the two arrays to find common elements, to let the user know how many correct guesses the user made compared to the random numbers array? For this part, I am only allowed to use loops.
I have tried using continue; below the first If, but that messes things up.
I have tried to move the ending curly brackets for the first for-loop to below the first If, but that also messes things up at the "compare the two arrays" part.
//User array
int[] användarTal = new int[10];
//Random numbers array
int[] slumpadeTal = new int[10];
//Generator for 10 random numbers.
Random randomerare = new Random();
//Foor-loop for storing user's 10 guesses in the user array.
for (int i = 0; i < användarTal.Length; i++)
{
Console.Write("Enter your guess: ");
string input = Console.ReadLine();
int num = Convert.ToInt32(input);
användarTal[i] = num;
//If the user enters wrong value
if (num < 1 || num > 25)
{
Console.WriteLine("Wrong! You must enter a number between 1-25!");
användarTal[i] = i--; //Wrong number will not be stored in the user array.
}
// continue;
// }
//For-loop for storing and writing out the 10 random numbers.
for (int j = 0; j < slumpadeTal.Length; j++)
{
Console.WriteLine(randomerare.Next(1, 26));
// Checking if the two arrays have any common numbers
if (användarTal[i] == slumpadeTal[j])
{
Console.WriteLine(användarTal[i]);
}
}
I found this solution which I have tried to implement into my program, but I can't get the program to run the way it's supposed to.
int[] arr1 = { 12, 5, 45, 47, 22, 10 };
int[] arr2 = { 23, 45, 10, 58, 78, 77, 46 };
for (int i = 0; i < arr1.Length; i++)
{
for (int j = 0; j < arr2.Length; j++)
{
if (arr1[i] == arr2[j])
{
Console.WriteLine(arr1[i]);
}
}
}
int[] arr1 = { 12, 5, 45, 47, 22, 10 };
int[] arr2 = { 23, 45, 10, 58, 78, 77, 46 };
for (int i = 0; i < arr1.Length; i++)
{
for (int j = 0; j < arr2.Length; j++)
{
if (arr1[i] == arr2[j])
{
Console.WriteLine(arr1[i]);
}
}
}
I dont see an issue with this code, seems like it should execute fine.
However you can optimise this using Linq
int[] array1 = { 12, 5, 45, 47, 22, 10 };
int[] array2 = { 23, 45, 10, 58, 78, 77, 46 };
int[] commonElements = array1.Intersect(array2);
Console.WriteLine("Common Elements: {0}", string.Join(",", commonElements));
See https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.intersect?view=net-7.0
It seems that you want to store and guess unique numbers only.
To be sure that numbers are unique, let's use HashSet<int> instead
of arrays:
using System.Linq;
...
// Random numbers array
HashSet<int> slumpadeTal = Enumerable
.Range(1, 25)
.OrderBy(item => Random.Shared.NextDouble())
.Take(10)
.ToHashSet();
Then let's ask user to guess
HashSet<int> användarTal = new HashSet<int>();
while (användarTal.Count < slumpadeTal.Count) {
while (true) {
Console.Write("Enter your guess: ");
if (int.TryParse(Console.ReadLine(), out int guess) &&
guess >= 1 && guess <= 25) {
användarTal.Add(guess);
break;
}
Console.WriteLine("Incorrect guess; it should be 1..25");
}
}
Having both collections filled in you can easily compare them
int guessedRight = slumpadeTal
.Count(item => slumpadeTal.Contains(item));

Zero padding a 2D array in C#

I currently have an issue with zero padding my 2d Array. I want to transfer my current data in my array to a new array, which is the exact same array but with a border of 0's around it.
Example:
|1 2 3|
|4 5 6|
|7 8 9|
Should become
|0 0 0 0 0|
|0 1 2 3 0|
|0 4 5 6 0|
|0 7 8 9 0|
|0 0 0 0 0|
int[,] Array = new int[,] { { 1, 2, 3 }, { 3, 4, 5 }, { 6, 7, 8 } };
int[,] ArrayZeroPad = new int[Array.GetLength(0) + 2, Array.GetLength(1) + 2];
for (int y = 0; y < Array.GetLength(1); y++)
{
for (int x = 0; x < ArrayZeroPad.GetLength(0); x++)
{
if (y == 0)
{ ArrayZeroPad[y, x] = 0; }
else if (y == ArrayZeroPad.GetLength(1))
{ ArrayZeroPad[y, x] = 0; }
else if (x == 0)
{
ArrayZeroPad[y, x] = 0;
}
else if (x == ArrayZeroPad.GetLength(0))
{ ArrayZeroPad[y, x] = 0; }
else ArrayZeroPad[y, x] = Array[y, x];
}
}
for (int y = 0; y < ArrayZeroPad.GetLength(1); y++)
{
Console.WriteLine();
for (int x = 0; x < ArrayZeroPad.GetLength(0); x++)
{ Console.Write(ArrayZeroPad[y, x]); }
Console.ReadLine();
}
}
This is what I have come to thus far, but I keep getting stuck on out of bounds errors, is there anyone who could work this out for me with some explanation?
Kind regards,
D.
This is not quite what you are asking (I thought a completely different alternative would be interesting).
Here is a No-Copy version that works for any type of array, of any size. It's appropriate if the original array is quite large (since it doesn't require a copy).
It uses a 2-dimensional indexer that either returns the default value of T (zero or null) for items on the edge, and uses the original array (with the indexes offset) for non-edge values:
public class ZeroPadArray <T>
{
private readonly T[,] _initArray;
public ZeroPadArray(T[,] arrayToPad)
{
_initArray = arrayToPad;
}
public T this[int i, int j]
{
get
{
if (i < 0 || i > _initArray.GetLength(0) + 1)
{
throw new ArgumentOutOfRangeException(nameof(i),
$#"Index {nameof(i)} must be between 0 and the width of the padded array");
}
if (j < 0 || j > _initArray.GetLength(1) + 1)
{
throw new ArgumentOutOfRangeException(nameof(j),
$#"Index {nameof(j)} must be between 0 and the width of the padded array");
}
if (i == 0 || j == 0)
{
return default(T);
}
if (i == _initArray.GetLength(0) + 1)
{
return default(T);
}
if (j == _initArray.GetLength(1) + 1)
{
return default(T);
}
//otherwise, just offset into the original array
return _initArray[i - 1, j - 1];
}
}
}
I just tested it with some Debug.Assert calls. The test coverage is weak, but it was good enough to say "this probably works":
int[,] array = new int[,] { { 1, 2, 3 }, { 11, 12, 13 }, { 21, 22, 23 } };
var paddedArray = new ZeroPadArray<int>(array);
Debug.Assert(paddedArray[0, 0] == 0);
Debug.Assert(paddedArray[4,4] == 0);
Debug.Assert(paddedArray[2,3] == 13);
And, finally, for fun, I added a nice little hack to make creating these things require less typing. When you call a method, the compiler is often able to deduce the generic type of the object from the method parameters. This doesn't work for constructors. That's why you need to specify new ZeroPadArray<int>(array) even though array is obviously an array of int.
The way to get around this is to create a second, non-generic class that you use as a static factory for creating things. Something like:
public static class ZeroPadArray
{
public static ZeroPadArray<T> Create<T>(T[,] arrayToPad)
{
return new ZeroPadArray<T>(arrayToPad);
}
}
Now, instead of typing:
var paddedArray = new ZeroPadArray<int>(array);
you can type:
var paddedArray = ZeroPadArray.Create(array);
Saving you two characters of typing (but, you need to admit that typing the <int> is frustrating).
int[,] Array = new int[,] { { 1, 2, 3 }, { 3, 4, 5 }, { 6, 7, 8 } };
int[,] ArrayZeroPad = new int[Array.GetLength(0) + 2, Array.GetLength(1) + 2];
for (int x = 0; x < ArrayZeroPad.GetLength(0); x++)
{
for (int y = 0; y < ArrayZeroPad.GetLength(0); y++)
{
//First row and last row
if (x == 0 || x == ArrayZeroPad.GetLength(0) - 1)
ArrayZeroPad[x, y] = 0;
else
{
//Fist column and last column
if (y == 0 || y == ArrayZeroPad.GetLength(0) - 1)
ArrayZeroPad[x, y] = 0;
else
{
//Content
ArrayZeroPad[x, y] = Array[x-1, y-1];
}
}
}
}
It seems that you are confusing dimensions - Array.GetLength(0) is for the first one in access Array[i, j] and Array.GetLength(1) is for the second. Also you can simplify copy by just scanning through Array elements and adjusting destination indexes by one, you don't need to explicitly set others to 0 cause it would be done for you (unless you are using stackalloc and skipping local init but I highly doubt that this is the case):
var length0 = Array.GetLength(0);
var length1 = Array.GetLength(1);
for (int i = 0; i < length0; i++)
{
for (int j = 0; j < length1; j++)
{
ArrayZeroPad[i + 1, j + 1] = Array[i, j];
}
}
And in the "print" method too - y should be the first dimension and x - second:
var length = ArrayZeroPad.GetLength(0);
for (int y = 0; y < length; y++)
{
Console.WriteLine();
var i = ArrayZeroPad.GetLength(1);
for (int x = 0; x < i; x++)
{
Console.Write(ArrayZeroPad[y, x]);
}
Console.ReadLine();
}
You can also solve this using Array.Copy(). If you require highest performance and the arrays are big enough, then this might be faster than explicitly copying each element:
public static int[,] Pad(int[,] input)
{
int h = input.GetLength(0);
int w = input.GetLength(1);
var output = new int[h+2, w+2];
for (int r = 0; r < h; ++r)
{
Array.Copy(input, r*w, output, (r+1)*(w+2)+1, w);
}
return output;
}
The (r+1)*(w+2)+1 requires some explanation. Array.Copy() treats a 2D array as a linear 1D array, and you must specify the destination offset for the copy as an offset from the start of the 1D array (in row-major order).
Since w is the width of the input array and r is the current row of the input array, the destination for the copy of the current input row will be the output row number, (r+1) times the output row width (w+2), plus 1 for to account for the left-hand column of 0 in the output array.
It's possible that using Buffer.BlockCopy() (which operates on bytes) could be even faster:
public static int[,] Pad(int[,] input)
{
int h = input.GetLength(0);
int w = input.GetLength(1);
var output = new int[h+2, w+2];
for (int r = 0; r < h; ++r)
{
Buffer.BlockCopy(input, r*w*sizeof(int), output, ((r+1)*(w+2)+1)*sizeof(int), w*sizeof(int));
}
return output;
}
As always, this is only worth worrying about if performance is critical, and even then only after you've benchmarked the code to verify that it actually is faster.

Find all differences in sorted array

I have a sorted (ascending) array of real values, call it a (duplicates possible). I wish to find, given a range of values [x, y], all indices of values (i) for which an index j exists such that:
j>i and
x <= a[j]-a[i] <= y
Or simply put, find values in which exists a “forward difference” within a given range.
The output is a Boolean array of length a.Length.
Since the array is sorted all forward differences, x and y are positive.
The best I’ve managed to do is start from each index looking at the subarray in front of it and perform a binary search for x+a[i] and check if a[j]<=y+a[i]. I think this is O(n log n).
Is there a better approach? Or something I can do to speed things up.
I should note that eventually I want to perform the search for many such ranges [x,y] over the same array a, but the number of ranges is very much smaller than the length of the array (4-6 orders of magnitude smaller) - therefore I’m far more concerned with the complexity of the search.
Example:
a= 0, 1, 46, 100, 185, 216, 285
with range x,y=[99,101] should return:
[true, true, false, false, true, false, false]
For only values 0,1 and 185 have a forward difference within the range.
Code from memory, might have some bugs:
int bin_search_closesmaller(int arr[], int key, int low, int high)
{
if (low > high) return high;
int mid = (high - low)/2;
if (arr[mid] > key) return bin_search_closesmaller(arr, key, low, mid - 1);
if (arr[mid] < key) return bin_search_closesmaller(arr, key, mid + 1, high);
return mid;
}
bool[] findDiffs(int[] a, int x, int y)
{
bool[] result = new bool[a.Length];
for(int i=0; i<a.Length-1;i++)
{
int idx=bin_search_closesmaller(a, y+a[i], i+1, a.Length-1);
if (idx==-1) continue;
if (a[idx]-a[i] >= x) result[i]=true;
}
}
Thanks!
Make two indexes left and right and walk through array. Right index moves until it goes out of range for current left one, then check whether previous element is in range. Indexes move only forward, so algorithm is linear
right=2
for left = 0 to n-1:
while A[right] < A[left] + MaxRangeValue
right++
Result[left] = (A[right - 1] <= A[left] + MinRangeValue)
Another point of view on this algorithm:
-while difference is too low, increment right
-while difference is too high, increment left
As long as the input array is sorted, there is a linear solution to the problem. The key is to use two indexes to traverse of the array a.
bool[] findDiffs(int[] a, int x, int y)
{
bool[] result = new boolean[a.Length];
int j = 0;
for (int i = 0; i < a.Length; ++i) {
while (j < a.Length && a[j] - a[i] < x) {
++j;
}
if (j < a.Length) {
result[i] = a[j] - a[i] <= y;
}
}
return result;
}
With a = [0,100,1000,1100] and (x,y) = (99,100):
i = 0, j = 0 => a[j] - a[i] = 0 < x=99 => ++j
i = 0, j = 1 => a[j] - a[i] = 100 <= y=100 => result[i] = true; ++i
i = 1, j = 1 => a[j] - a[i] = 0 < x=99 => ++j
i = 1, j = 2 => a[j] - a[i] = 900 > y=100 => result[i] = false; ++i
i = 2, j = 2 => a[j] - a[i] = 0 <= x=99 => ++j
i = 2, j = 3 => a[j] - a[i] = 100 <= y=100 => result[i] = true; ++i
i = 3, j = 3 => a[j] - a[i] = 0 <= x=99 => exit loop

Display every digit of values of array

I have an array of numbers and I want to display the last digit first, then the 2nd, 3rd, and so on.. How do I do that?
for example, I have: 123, 210, 111
It will display 3, 0, 1, first
then 2, 1, 1,
last, 1, 2, 1
I have this as my code:
for(int x = 0; x < 3; x++){
string n = num[x].ToString(); //converting the array to string
for(int y = length-1; y>=0; y++) //length = number of digits
Console.Write(c[y] + "\n");
}
But it displays the digits of the 1st number first, then the 2nd num, and the 3rd. (3, 2, 1, 0, 1,2, 1,1,1)
You just need to reverse the order of the loops and decrease the letter loop counter:
for(int y = length - 1; y>=0; y--) //length = number of digits
{
for(int x = 0; x < 3; x++){
string n = num[x].ToString(); //converting the array to string
Console.Write(n[y] + "\n");
}
}
Firstly you want to be decreasing your loop counter. Also what is the array c? you have assigned the number to 'n' earlier
Not that clean but w.e.
int[] myInts = { 123, 210, 111 };
string[] result = myInts.Select(x => x.ToString()).ToArray();
int k = 0;
for (int i = 3; i > 0; i--)
{
while (k < 3)
{
Console.Write(result[k].Substring(i - 1, 1));
k++;
}
k = 0;
Console.WriteLine();
}

Add Int[] array into List<int[]>

I'm having trouble with int[] arrays and adding them to a List<>. I'd like to add the values of my int[] array to something each loop but every time I do this my "something" gets the same value for every element I add. Very annoying. I understand arrays are always reference vars. However even the "new" key word doesn't seem to help. What needs to happen is to add result to some enumerated object like a List or Array or ArrayList.
Here's the codility question:
You are given N counters, initially set to 0, and you have two possible operations on them:
increase(X) − counter X is increased by 1,
max_counter − all counters are set to the maximum value of any counter.
A non-empty zero-indexed array A of M integers is given. This array represents consecutive operations:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max_counter.
For example, given integer N = 5 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
I copied some code from others and the variable "result" does indeed load the data correctly. I just wanted to copy it back to the main program so I could see it. The only method that works is += add it into a string. Thus losing any efficiency I might have gained.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace testarray
{
class Program
{
static void Main(string[] args)
{
int[] A = new int[7];
A[0] = 3;
A[1] = 4;
A[2] = 4;
A[3] = 6;
A[4] = 1;
A[5] = 4;
A[6] = 4;
List<int[]> finish = solution(5, A);
}
public static List<int[]> solution(int N, int[] A)
{
int[] result = new int[N];
int maximum = 0;
int resetlimit = 0;
int iter = 0;
List<int[]> collected_result = new List<int[]>;
for (int K = 0; K < A.Length; K++)
{
if (A[K] < 1 || A[K] > N + 1)
{
throw new InvalidOperationException();
}
if (A[K] >= 1 && A[K] <= N)
{
if (result[A[K] - 1] < resetlimit)
{
result[A[K] - 1] = resetlimit + 1;
}
else
{
result[A[K] - 1]++;
}
if (result[A[K] - 1] > maximum)
{
maximum = result[A[K] - 1];
}
}
else
{
resetlimit = maximum;
result = Enumerable.Repeat(maximum, result.Length).ToArray<int>();
}
collected_result.Add(result);
}
// for (int i = 0; i < result.Length; i++)
//result[i] = Math.max(resetLimit, result[i]);
return collected_result;
}
}
}
This doesn't work, the collected_result ends up like:
(0,0,1,2,0)
(0,0,1,2,0)
(0,0,1,2,0)
(3,2,2,4,2)
(3,2,2,4,2)
(3,2,2,4,2)
(3,2,2,4,2)
I know it's the line collected_result.Add(result); adding the reference each time to every instance of result in the List<>. Bother. I've tried adding "new" which is a compiler error. Finally in desperation I just added everything to a very long string. Can someone help me figure out how to properly load an object to pass back to main?
Easiest way to go:
Get a copy of your array before adding it to list:
collected_result.Add(result.ToArray());
Here is a Python solution:
def solution(A, N):
lenA = len(A)
k = 0
max_counter_value = 0
counters = [0 for x in range(0, N)]
for k in range(0, lenA):
if A[k] >= 1 and A[k] <= N:
counters[A[k] - 1] += 1
max_counter_value = max(counters)
if A[k] == N + 1:
counters = [max_counter_value for x in range(0, N)]
print counters
A = [3, 4, 4, 6, 1, 4, 4]
N = 5
solution(A, N)

Categories

Resources