I need an array of the same dimensions (to hold values 0 or 1) as an argument to a function which may be of any rank and any type. The result array will contain 0 for failure and 1 for success (I could use Boolean) arising from a process. How can I create the result array?
Use Array.CreateInstance:
private static Array CreateArray(Array array)
{
List<int> dimensions = new List<int>();
for (int i = 0; i < array.Rank; i++)
{
dimensions.Add(array.GetLength(i));
}
return Array.CreateInstance(typeof(bool), dimensions.ToArray());
}
Related
string[] n = Console.ReadLine().Split();
for (int i = 1; i <6; i++)
{
int[] a = long.Parse(n[i]);
}
If each number in a row separated with whitespace - you can use your Split more efficiently:
int[] array = Console.ReadLine().Split().Select(int.Parse).ToArray(); // Improved according to #Caius Jard comment
If need array of longs - replace int.Parse with long.Parse and declare variable as long[] array.
You need to add using System.Linq to get access to ToArray extension method.
EDIT.
Insprired by #Caius Jard, non-LINQ version:
// Read input line and split it by whitespace (default)
string[] values = Console.ReadLine().Split();
// Declare arrays for Int or Long values.
// Arrays sizes equals to size of array of input values
int[] arrayOfInts = new int[values.Length];
long[] arrayOfLongs = new long[values.Length];
// Iterate with for loop over amount of input values.
for (int i = 0; i < values.Length; i++)
{
// Convert trimmed input value to Int32
arrayOfInts[i] = int.Parse(values[i].Trim());
// Or to Int64
arrayOfLongs[i] = long.Parse(values[i].Trim());
}
int.Parse and long.Parse may be replaced with Convert.ToInt32 and Convert.ToInt64 if needed.
Please, don't use magic constants: i < 6. Here 6 doesn't necessary equal to n.Length.
You can put it as
string[] n = Console.ReadLine().Split();
List<int> list = new List<int>();
for (int i = 0; i < n.Length; ++i) {
if (int.TryParse(n[i], out int value))
list.Add(value);
else {
// Invalid item within user input, say "bla-bla-bla"
//TODO: either reject the input or ignore the item (here we ignore)
}
}
if (list.Count == a.Length) {
// We have exactly a.Length - 6 valid integer items
for (int i = 0; i < a.Length; ++i)
a[i] = list[i];
}
else {
//TODO: erroneous input: we have too few or too many items
}
This question already has answers here:
How do I check if my array has repeated values inside it?
(8 answers)
Closed 5 years ago.
I would like to check the array I passed in the shuffle method for any duplicates.
I would like to also generate a random number that is the size of a.length.
The thing is that I can't figure out how to check if the array has duplicates and if it does it would generate another number until it is unique from the rest.
public int[] Shuffle(int[] a)
{
//check if the array has duplicates
for (int i = 0; i < a.Length; i++)
{
int curValue = random.Next(a.Length);
if(a.Contains(curValue))
{
curValue = random.Next(a.Length);
}
else
{
a[i] = curValue;
}
}
for (int i = 0; i < a.Length; i++)
{
int r = random.Next(a.Length);
int t = a[r];
a[r] = a[i];
a[i] = t;
}
return a;
}
Can anyone help me?
Here is a function that does what you ask as I presume. Include using System.Linq to run it. I went on the basis of your text, because the code did not make your question clear to me. If you meant something differently please clarify.
static int[] Shuffle(int[] a)
{
Random rnd = new Random();
//Remove duplicates from array
int[] distinct = a.Distinct().ToArray();
//Add the same amount of unique numbers that have been removed as duplicates
int len = a.Length - distinct.Length;
int[] newNumbers = new int[len];
int i = 0;
while(i < len)
{
newNumbers[i] = rnd.Next(a.Length); //NOTE: here i put in the length of array a, but with an int array this will always resolve in a shuffled array containing all digits from 0 to the length-1 of the array.
if (!distinct.Contains(newNumbers[i]) && !newNumbers.Take(i).Contains(newNumbers[i]))
{
++i;
}
}
//Randomize the array
int[] b = a.OrderBy(x => rnd.Next()).ToArray();
//Concatenate the two arrays and return it (shuffled numbers and new unique numbers)
return distinct.Concat(newNumbers).ToArray();
}
As I said in the note, if you remain with an integer array and only allow adding of new random replacement number lower than the length of the array, you and up with a shuffled array of all numbers from 0 to the array length.
Since a new array for newNumbers is generated, you also need to check if a newly generated number is not in that array.
I'm trying to serialize multidimensional arrays with any number of dimensions. Note that I'm referring to actual multidimensional arrays (float[,]), not jagged arrays (float[][]).
After serializing the length of each dimension, I can easily serialize each element using foreach (var item in array).
But when deserializing I can't use foreach because I need to assign the values. I know that I'll need to use array.SetValue(object value, params int[] indices), but I can't wrap my head around how to set up a loop to do what you would normally do with one nested for loop for each dimension.
First, serialize the original array using a foreach loop. It will flatten the array.
Then, read the values in the same way the were serialized (code is based on the array's enumerator)
var original = new int[2,2,2] { { { 1, 2 }, { 3, 4} }, { { 5, 6 }, { 7, 8 } } };
var serialized = original.Cast<int>().ToArray();
var originalBounds = Enumerable.Range(0, original.Rank)
.Select(i => original.GetUpperBound(i) + 1).ToArray();
var empty = Array.CreateInstance(typeof(int), originalBounds);
var indices = new int[empty.Rank];
indices[indices.Length - 1]--;
var index = 0;
while (IncArray(empty, indices))
{
empty.SetValue(serialized[index++], indices);
}
private bool IncArray(Array array, int[] indices)
{
int rank = array.Rank;
indices[rank - 1]++;
for (int i = rank - 1; i >= 0; i--)
{
if (indices[i] > array.GetUpperBound(i))
{
if (i == 0)
{
return false;
}
for (int j = i; j < rank; j++)
{
indices[j] = 0;
}
indices[i - 1]++;
}
}
return true;
}
This approach would allow you to read the values from a stream - you don't need to create the serialized array like I have.
Another way is to use Buffer.BulkCopy. Here you'd have to read the entire array, at least into bytes, and calculate the amount of bytes you need to copy. The advantage here is that you avoid all the boxing in the previous method, and that it's simpler:
var bytes = new byte[...]; // read the entire byte array
var empty = Array.CreateInstance(typeof(int), originalBounds);
Buffer.BlockCopy(bytes, 0, empty, 0, bytes.Length);
I like to create an int[] with length X and value it with [0,1,2....X]
e.g.
public int[] CreateAA(int X){}
int[] AA = CreateAA(9) => [0,1,2,3,4,5,6,7,8,9]
is there any easy method? Or have to loop and init value
You can avail the functionality of IEnumerable.
int[] arr = Enumerable.Range(0, X+1).ToArray();
This will create a IEnumerable List for you and .ToArray() will satisfy your int array need.
So for X=9 in your case it would generate the array for [0,1,2,3,4,5,6,7,8,9] (as you need)
Using Enumerable.Range(0, 10).ToArray() is very concise but if you want to create a very large array the ToArray extension method will have to collect the numbers into a buffer that will have to be reallocated multiple times. On each reallocation the contents of the buffer is copied to the new larger buffer. .NET uses a strategy where the size of the buffer is doubled on each reallocation (and the initial buffer has four items).
So if you want to avoid multiple reallocations of the buffer you need to create the array in advance:
int[] aa = new int[10];
for (var i = 0; i < aa.Length; i += 1)
aa[i] = i;
This is the most efficient way of initializing the array.
However, if you need an array of say 100,000,000 consecutive numbers then you should look at a design where you don't have to keep all the numbers in an array to avoid the impact of the memory requirement. IEnumerable<int> is very useful for this purpose because you don't have to allocate the entire sequence but can produce it while you iterate and that is exactly what Enumerable.Range does. So avoiding the array of consecutive numbers in the first place may be even better than thinking about how to create it.
Why make a function when it is already there.
For this specific example, use
int[] AA = Enumerable.Range(0, 10).ToArray();
where 0 is the starting value and 10 (X + 1) is the length of array
So a general one applicable to all
int[] AA = Enumerable.Range(0, X + 1).ToArray();
with function and loop:
static int[] f(int X)
{
int[] a = new int[X+1];
for(int i = 0; i < a.Length; i++)
a[i] = i;
return a;
}
To initialize try this
int x = 10;
Enumerable.Range(0, x)
.Select((v, i) => v + i).ToArray();
For completeness, here is a function that creates an array.
I made it a bit more versatile by having parameters for the min and max value, i.e. CreateArray(0, 9) returns {0,1,2,3,4,5,6,7,8,9}.
static int[] CreateArray(int min, int max) {
int[] a = new int[max - min + 1];
for (int i = 0; i < a.Length; i++) {
a[i] = min + i;
}
return a;
}
I need to iterate over an array of arbitrary rank. This is for both reading and writing, so GetEnumerator will not work.
Array.SetValue(object, int) doesn't work on multidimensional arrays.
Array.SetValue(object, params int[]) would require excessive arithmetic for iterating through the multidimensional space. It would also require dynamic invocation to get around the params part of the signature.
I'm tempted to pin the array and iterate over it with a pointer, but I can't find any documentation that says that multidimensional arrays are guaranteed to be contiguous. If they have padding at the end of a dimension then that won't work. I'd also prefer to avoid unsafe code.
Is there an easy way to sequentially address a multidimensional array using only a single index?
Multidimensional arrays are guaranteed to be contiguous. From ECMA-335:
Array elements shall be laid out within the array object in row-major order (i.e., the elements associated with the rightmost array dimension shall be laid out contiguously from lowest to highest index).
So this works:
int[,,,] array = new int[10, 10, 10, 10];
fixed (int* ptr = array)
{
ptr[10] = 42;
}
int result = array[0, 0, 1, 0]; // == 42
You can use the Rank and GetUpperBound property/method to create an indices array that you can pass to the array's SetValue and GetValue methods:
int[] Indices(Array a, int idx)
{
var indices = new int[a.Rank];
for (var i = 0; i < a.Rank; i++)
{
var div = 1;
for (var j = i + 1; j < a.Rank; j++)
{
div *= a.GetLength(j);
}
indices[i] = a.GetLowerBound(i) + idx / div % a.GetLength(i);
}
return indices;
}
..and use it like so:
for (var i = 0; i < array.Length; i++)
{
var indices = Indices(array, i);
array.SetValue(i, indices);
var val = array.GetValue(indices);
}
Perhaps you could join them all into the a single temporary collection, and just iterate over that.