IEnumerable, .ElementAt and unsigned/signed indices in C#? - c#

This is just a language curiosity rather than problem.
The ElementAt() method of IEnumerable accepts integers to get the Nth element of an enumerable collection.
For example
var list = new List<char>() { 'a', 'b', 'c' };
var alias = list.AsEnumerable();
int N = 0;
alias.ElementAt(N); //gets 'a'
All good, however, why doesn't ElementAt() accept unsigned integers (uint) ?
e.g.
uint N = 0;
alias.ElementAt(N); //doesn't compile
I can understand why ElementAt could accept integers to allow negative indices (e.g. Python allows negative indices where list[-1] refers to the last element), so it makes sense to have accept negative indices for those languages that do use them even if C# doesn't.
But I can't quite see the reasoning for disallowing unsigned integers, if anything an unsigned integer is better as it guarantees that the index will not be negative (so only the upper bound of the range needs to be checked).
The best thing I could think of is perhaps the CLR team decided to standardize on signed integers to allow other languages (e.g. Python) that do have negative indices to use the same code and ensure the ranges would consistent across languages.
Does anyone have a better/authoritative explanation for why .ElementAt() doesn't allow unsigned ints ?
-Marcin

The real reason is that .NET arrays can be non-zero based, even if C# language does not support declaring such arrays. You can still create them using Array.CreateInstance Method (Type, Int32[], Int32[]).
Note the special name of the type of the created object (System.Int32[*]) with an asterisk in it.
List is implemented using array internally, and it would not be practical to use different type for indexing.
Also, Count property usually participates in array index calculation, in which a partial result could be negative. Mixing types in an expression would be cumbersome and error prone.
Having a type which can't represent negative index would not help in error detection.
Using automatical clipping with unchecked operation would not fix logical array index computation errors in an application anyway.
Following example shows negative-based array manipulation C#:
var negativeBasedArray = Array.CreateInstance(typeof(Int32),
new []{2}, // array of array sizes for each dimension
new []{-1}); // array of lower bounds for each dimension
Console.WriteLine(negativeBasedArray.GetType()); // System.Int32[*]
negativeBasedArray.SetValue(123, -1);
negativeBasedArray.SetValue(456, 0);
foreach(var i in negativeBasedArray)
{
Console.WriteLine(i);
}
// 123
// 456
Console.WriteLine(negativeBasedArray.GetLowerBound(0)); // -1
Console.WriteLine(negativeBasedArray.GetUpperBound(0)); // 0

Related

Negative index arrays in .NET

The Array.BinarySearch(Array array, object value) method's documentation mentions that
This method does not support searching arrays that contain negative indexes.
If you look at its source, there's a comment inside the GetMedian(int low, int hi) method that states:
// Note both may be negative, if we are dealing with arrays w/ negative lower bounds.
Contract.Requires(low <= hi);
Correct me if I'm wrong, but C# by itself has no notion of negative-index arrays and there is no such thing as an array's lower bound (like an Array.LowerBound property or something). That would lead me to the conclusion that while C# does not, CLR itself does allow negatively indexed arrays. Am I correct? Is there a .NET language that has such arrays? Why would you even have such arrays in the first place?
Bonus imaginary points if there's a reflection voodoo ritual one can perform to get a negatively indexed array in C# and break the fabric of reality.

Does the length of a newly instantiated array resolve to 0 or null?

HOMEWORK: I'm getting and index out-of-bounds on the following code. It's a hangman game, and I'm keeping track of the letters I've guessed in a char array.
Here's the assumptions I made:
In the calling method, I have an unpopulated array (char[] displayGuesses = new char[26];) passing to the method below as the char[] usedLetters parameter.
The first iteration of the letter-guessing, the array will be empty.
It's length will be 0.
I populate usedLetters[0] with the letterGuessed parameter.
The next time I guess, length of the array will be 1, so usedLetters[1] gets populated...and so on.
public char[] trackUsedLetters(char letterGuessed, char[] usedLetters)
{
int letterIndex = usedLetters.Length;
usedLetters[letterIndex] = letterGuessed;
return usedLetters;
}
There's a couple things I think may be going on.
When I try to get the length of usedLetters on the first run, the empty array does
NOT return zero, but null. Boom. Out-of-bounds.
There's some issue with passing a blank array defined with 26
members...? But I'm not sure what that issue would even BE, so I have no idea what to google that will yield relevant results.
I may have a scope issue; I found this link to a similar
question for Java, though using a for loop. I don't quite get
what the Java user was going for, but some of the problems sounded
familiar.
I need a second pair of eyes to look at this and point me in the right direction for solving this.
According to the c# specification: (emphasis mine)
1.8 Arrays
Array types are reference types, and the declaration of an array variable simply sets aside space for a reference to an array instance. Actual array instances are created dynamically at run-time using the new operator. The new operation specifies the length of the new array instance, which is then fixed for the lifetime of the instance. The indices of the elements of an array range from 0 to Length - 1. The new operator automatically initializes the elements of an array to their default value, which, for example, is zero for all numeric types and null for all reference types.
Default Values which gives the char data type default as '\0'
It looks like you want List<char> that can grow (with Add) method.
Arrays have fixed size and following code (that you have in sample) will always throw out of range exception because you are accessing element past last element in array.
usedLetters[usedLetters.Length] = 'c';
More details on array length:
// newArray - array of 0 chars. newArray.Length is 0
var newArray = new char[0];
// nullArray not created, nullArray.Length will throw NullReferenceExcetption
char[] nullArray = null;
// defaultArray = array of 26 characters, each value 0.
// defaultArray.Length is 26;
char[] defaultArray = new char[26];
When you define a new array, but don't manually initialize the items inside of it, it will automatically be initialized with the default values for whatever type the array contains. In your case, you're creating a character array. The default value for a char is '\0', or the null character.
This means that the array is never truly "empty." If you define an array with 26 slots, it will always have that length, unless you make a new array.

How to get number of elements in an array, Extension Method Count() and Length gives the size of Array.

Hi I was trying to find the number of elements in an array
byte[] salt = new byte[32];
now I only have mentioned size 32 so the Length Property of Array and Enumerable's Count Method will give me 32.
Even if I will iterate on this Array salt using for or foreach or any other looping construct it will iterate 32 times and on each index the value is 0 (i.e default value of byte)
Now suppose I do:
for (int i = 0; i < 5 ; i++)
{
salt[i] = 4-i;
}
And I want to know how many elements are inserted sequentially in Array starting from index 0, Here you may say are you fool you iterating it 5 times and you know the number is 5 , but I am having heavy looping and other logic (appending prepending to another arrays of byte) in it. *My question Is there any other inbuilt function that could give me this number 5 ? * Even if I iterate and check for first default value and break the loop there and get the count but there might be the chance last value inserted is 0 like above salt[4] is 0 so that iterating will give me the count 4 which is incorrect . If I am not wrong I think when we declare Array with size like 32 above 32 consecutive memory bytes are reserved and you are free to insert at any index from 0-31 and its your responsibility to keep the track where and how and how many elements are assigned to Array .I hope you got my point And thanks in advance for help.
An array is an array, and in .NET is initialized when it is allocated. Once it's initialized, the question of whether a given value is uninitialized or simply 0 isn't something that's possible to check. A 0 is a 0.
However, you can bypass that in several ways. You can use a List<int>, like #SLaks suggested, to have a dynamically allocated list that's only initialized with the elements you want.
You can also use, instead of an array of int, and array of int?, so a null value isn't the same as a 0.
Short answer is you can't, the array contains 32 integers, .net framework doesn't care if some of them are 0, so you can create your own function that counts how many integers from an array are different than 0, or keep a "count" when you assign values for array elements or something like that.
Or you can use another container, example a list and dynamically add or remove integers from it.
Ok, when you define an array as int[] myArray = int[32]; you are saying, I HAVE 32 ints. Not, create me space for 32 ints that I will fill in later. That's why count is giving you 32.
If you want something which you can genuinly add to and resize, you need to use a List (or one of it's relatives.
If you want to have a "cap" for a list, I found this :Maximum capacity collection in c#

The use of LinkedList<BigInteger>

I've been struggling for a while now with an error I can't fix.
I searched the Internet without any success and started wandering if it is possible what I want to accomplish.
I want the create an array with the a huge amount of nodes, so huge that it I need BigInteger.
I founded that LinkedList would fit my solution the best, so I started with this code.
BigInteger[] numberlist = { 0, 1 };
LinkedList<BigInteger> number = new LinkedList<BigInteger>(numberlist);
for(c = 2; c <= b; c++)
{
numberlist [b] = 1; /* flag numbers to 1 */
}
The meaning of this is to set all nodes in the linkedlist to active (1).
The vars c and b are bigintegers too.
The error I get from VS10 is :
Cannot implicitly convert type 'System.Numerics.BigInteger' to 'int'. An explicit conversion exists (are you missing a cast?)
The questions:
Is it possible to accomplish?
How can I flag all nodes in number with the use of BigInteger (not int)?
Is there an other better method for accomplishing the thing?
UPDATE
In the example I use c++ as the counter. This is variable though...
The node list could look like this:
numberlist[2]
numberlist[3]
numberlist[200]
numberlist[20034759044900]
numberlist[23847982344986350]
I'll remove processed nodes. At the maximum I'll use 1,5gb of memory.
Please reply on this update, I want to know whether my ideas are correct or not.
Also I would like too learn from my mistakes!
The generic argument of LinkedList<T> describes the element type and has nothing to do with the number of elements you can put in the collection.
Indexing into a linked list is a bad idea too. It's an O(n) operation.
And I can't imagine how you can have more elements than what fits into an Int64. There is simply not enough memory to back that.
You can have more than 2^31-1 elements in a 64bit process, but most likely you need to create your own collection type for that, since most built in collections have lower limits.
If you need more than 2^31 flags I'd create my own collection type that's backed by multiple arrays and bitpacks the flags. That way you get about 8*2^31 = 16 billion flags into a 2GB array.
If your data is sparse you could consider using a HashSet<Int64> or Dictionary<Int64,Node>.
If your data has long sequences with the same value you could use some tree structure or perhaps some variant of run-length-encoding.
If you don't need the indexes at all, you could just use a Queue<T> and dequeue from the beginning.
From your update it seems you don't want to have huge amount of data, you just want to index them using huge numbers. If that's the case, you can use Dictionary<BigInteger, int> or Dictionary<BigInteger, bool> if you only want true/false values. Alternatively, you could use HashSet<BigInteger>, if you don't need to distinguish between false and “not in collection”.
LinkedList<BigInteger> is a small number of elements, where each element is a BigInteger.
.NET doesn't allow any single array to be larger than 2GB (even on 64-bit), so there's no point in having an index larger than an int.
Try breaking your big array into smaller segments, where each segment can be addressed by an int.
If I may read your mind, it sounds like what you want a sparse array which is indexed by a BigInteger. As others have mentioned, LinkedList<BigInteger> is entirely the wrong data structure for this. I suggest something entirely different, namely a Dictionary<BigInteger, int>. This allows you to do the following:
Dictionary<BigInteger, int> data = new Dictionary<BigInteger, int>();
BigInteger b = GetBigInteger();
data[b] = 1; // the BigInteger is the *index*, and the integer is the *value*

How to create a 1-Dimensional Array in C# with index starting at 1

For multidimensional arrays Array.CreateInstance can be used to create non-zero index based arrays, but if you try that for a 1-dimensional arrays (vectors) as in e.g.:
public double[] myArray = (double[])Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });
this will fail at run-time when the cast from the the multidimensional Array to a single-dimensional array fails
"Unable to cast object of type 'System.Double[*]' to type 'System.Double[]'"
Now I could just create a zero based array and ignore the first value, or work with offsets etc., but am I overlooking some c# syntactic magic that allows for non zero based vectors?
Update:
I'll take Eric Lippert's word for it if he says "There's no obvious way to make a non-zero-based array in C#"
You can make a non-zero-based array in C#, but the useage of it is kind-of obnoxious. It is definitly not a simple substitute for a normal (i.e., zero-based single dimentional) array.
// Create the array.
Array myArray = Array.CreateInstance(typeof(double), new int[1] { 12 }, new int[1] { 1 });
// Fill the array with random values.
Random rand = new Random();
for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
{
myArray.SetValue(rand.NextDouble(), index);
}
// Display the values.
for (int index = myArray.GetLowerBound(0); index <= myArray.GetUpperBound(0); index++)
{
Console.WriteLine("myArray[{0}] = {1}", index, myArray.GetValue(index));
}
The GetValue/SetValue syntax that is required for this is uglier than subtracting one from a vector index at each occurance.
If a value type is stored in the array, then it will be stored in consecutive position just as in a regular array, but the getter and setter will require boxing of the values (unless there is some compiler magic that I am not aware of). And the getter will usually require a cast (just to make it even uglier).
double myValue = (double)myArray.GetValue(index);
Also note that the correct comparison for GetUpperBound is <=, unlike Length which is compared with <.
Non-Zero based arrays DO exist in C, and there IS a way to create a 1's (or whatever) based array.
I fully agree that they are messy, and they should not be used for anything other than legacy stuff, but they are ESSENTIAL to interact with old COM libraries.
The most common place to run into this is working with the Microsoft.Office.Interop.Excel.Range object in the Excel library which still uses the old DCOM interface underneath.
Example:
/// <summary>
/// Makes the equivalent of a local Excel range that can be populated
/// without leaving .net
/// </summary>
/// <param name="iRows">number of rows in the table</param>
/// <param name="iCols">number of columns in the table</param>
/// <returns>a 1's based, 2 dimensional object array which can put back to Excel in one DCOM call.</returns>
public static object[,] NewObjectArray(int iRows, int iCols)
{
int[] aiLowerBounds = new int[] { 1, 1 };
int[] aiLengths = new int[] { iRows, iCols};
return (object[,])Array.CreateInstance(typeof(object), aiLengths, aiLowerBounds);
}
In this case, the reason this code is necessary is each DCOM call to excel is a cross-process call, and if you were to access cells one-at-a-time, you'd incur huge overhead, (either retrieving or setting values). An Excel range is a 1's based 2 dimensional array, and if one creates the array, and populates it locally, it can be pushed to excel in one cross-process call, creating an enormous performance improvement.
If anybody is still looking for a one-based array implementation, here is a one-dimensional generic one-based array, which is just a wrapper type on a regular array:
https://github.com/ColmBhandal/CsharpExtras/blob/master/CsharpExtras/Enumerable/OneBased/OneBasedArray.cs
There is also a two-dimensional version, but no higher dimensional versions as of yet (this code was written to support Excel, so 2D was all that was needed):
https://github.com/ColmBhandal/CsharpExtras/blob/master/CsharpExtras/Enumerable/OneBased/OneBasedArray2D.cs
Both of these types have test written for them in an associated test project under the same repo:
https://github.com/ColmBhandal/CsharpExtras/tree/master/CsharpExtrasTest/OneBased
Disclaimer: these repos are hosted on my personal GitHub account and are open source.
All arrays in C# are zero based. As far as I know there is no way to create a 1 based array. Imagine what kind of a mess would have happened if that was possible. Here is a similar thread which explains the issue with more details - C#: Nonzero-based arrays are not CLS-compliant

Categories