When I try run the aplication, it shows the Index was outside the bounds of the array at line float[] u_f = a[userid]; when I check the value of userid, it is -1;
Any idea?
PS. the user ID can be every integer,but I take the index of the integer with is between(0, 1143600 for item) and (0, 89395 for user) and my calculation is based on that.Then, my calculation is based on the index of userid value which is stored in array a not based on the value of userid.
Thanks in advance.
float[][] a = Enumerable.Range(0, 89395).Select(i => new float[100]).ToArray();
float[][] b = Enumerable.Range(0, 1143600).Select(j => new float[100]).ToArray();
int[] c = new int[1258038];
int[] d = new int [92160];
........
public float dotproduct(int userid, int itemid)
{
result = 0f;
float[] u_f = a[userid]; // <----Error Line (index was outside the bounds of array-The value of user id is -1)
float[] i_f = b[itemid];
for (int i = 0; i < u_f.Length; i++)
{
result += u_f[i] * i_f[i];
}
return result;
}
private void btn_recomm_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(txtbx_id.Text) && String.IsNullOrEmpty(txtbx_itemid.Text) && !String.IsNullOrEmpty(txtbx_noofrecomm.Text))
{
int sc = Convert.ToInt32(txtbx_id.Text);
int n = Convert.ToInt32(txtbx_noofrecomm.Text);
int userseq=Array.IndexOf(d, sc);
var results = new List<float>(1143600);
for (int z = 0; z <= 1143600; z++)
{
results.Add(dotproduct(userseq, z));
}
var sb1 = new StringBuilder();
foreach (var resultwithindex in results.Select((r, index) => new { result = r, Index = index }).OrderByDescending(r => r.result).Take(n))
{
sb1.AppendFormat("{0}: {1}", d[resultwithindex.Index], resultwithindex.result);
sb1.AppendLine();
}
MessageBox.Show(sb1.ToString());
}
if (!String.IsNullOrEmpty(txtbx_id.Text) && !String.IsNullOrEmpty(txtbx_itemid.Text) && String.IsNullOrEmpty(txtbx_noofrecomm.Text))
{
int uid = Convert.ToInt32(txtbx_id.Text);
int iid = Convert.ToInt32(txtbx_itemid.Text);
int userseq0 = Array.IndexOf(d, uid);
int itemseq0 = Array.IndexOf(c, iid);
dotproduct(userseq0, itemseq0);
MessageBox.Show("The Score of item id " + itemseq0 + " is " + result);
}
Your problem is this line:
int userseq=Array.IndexOf(d, sc);
is presumably returning -1 which you are then passing into your dotproduct function which is then causing it to fail. You need to decide on what logic to apply in the case that you can't find sc in d and implement that.
Though as others have said validating your input to dotproduct would help you find problems a bit more easily.
I am not sure what you are asking. You have an error because you are try to access to the index -1 of a. An array begin at 0. The value -1 does not exist. userid should be between 0 and a.Length.
Is your method supposed to accept a userid value that's inferior to zero? If so then you cannot use that to define an array's length. Period.
If -1 is not a valid value, I would add this right on the first line of your dotproduct method, since it's public:
if (userid < 0) throw new ArgumentOutOfRangeException("userid");
As for why it's -1 in the current context, as others pointed out if the text value you try to find in the d array isn't there, the IndexOf method will return -1. You will have to validate the user's input before calling in your method.
I will also say what I already told you in your other post: name your variables in a clear way and - if that makes sense in your scenario - use custom classes rather than jagged arrays. Your code will be far easier to read and maintain afterwards.
int userseq=Array.IndexOf(d, sc);
it returns -1 if item sc is not present in array d. Then you pass userseq variable as first argument of a function dotproduct and take array index by it's first argument (userid). So here is your problem - in the IndexOf.
I don't know how to fix it - it's your buiseness logic and you must decide how to handle the case when input data isn't present in array. Maybe show message to user immediately.
Related
EDIT: OP here, its answered. Can't accept my own answer for 2 days? Dunno I'm a stack noob. Thanks to people that helped.
I want to have a loop that generates a random coordinate and adds it to a list only if that coordinate does not already exist in the list.
And just keeps looping until the correct number of coordinates are in the list.
while (spawnPositions.Count < myPlayer.myPlayerUnits.Count)
{
Debug.Log("While");
int[,] rnd = new int[UnityEngine.Random.Range(minX, maxX), UnityEngine.Random.Range(minZ, maxZ)];
if (spawnPositions.Contains(rnd) == false)
{
Debug.Log("SpawnPos Added!");
spawnPositions.Add(rnd);
}
}
Problem is the if statement is always true. Console output shows the loop loops X amount of times and the if statement is also true X amount of times.
Is this just not possible to do in while-loop. Or am i doing something wrong? Thanks!
EDIT: Oh and to be clear yes duplicates are added. I'm trying to generate 5 unique coordinates on a 3x3 area and there is almost always duplicates!
If I understand you right you want to compare the content of multidimensional arrays or maybe only their dimensions. But the .Contains() method looks for the reference equality and this is always unique because you are calling "new".
I defined a extension method for it.
public static bool IsContentEqualTo(this int[,] array1, int[,] array2)
{
if (array1 == null) throw new ArgumentNullException(nameof(array1), "Array cannot be null");
if (array2 == null) throw new ArgumentNullException(nameof(array2), "Array cannot be null");
if (array1.GetLowerBound(0) != array2.GetLowerBound(0)) return false;
if (array1.GetUpperBound(0) != array2.GetUpperBound(0)) return false;
if (array1.GetLowerBound(1) != array2.GetLowerBound(1)) return false;
if (array1.GetUpperBound(1) != array2.GetUpperBound(1)) return false;
var xMin = array1.GetLowerBound(0);
var xMax = array1.GetUpperBound(0);
var yMin = array1.GetLowerBound(1);
var yMax = array1.GetUpperBound(1);
for (var x = xMin; x <= xMax; x++)
for (var y = yMin; y <= yMax; y++)
{
if (array1[x, y] != array2[x, y]) return false;
}
return true;
}
And you can call it like that.
if (!spawnPositions.Any(array => array.IsContentEqualTo(rnd)))
{
Debug.Log("SpawnPos Added!");
spawnPositions.Add(rnd);
}
EDIT: OP here, its answered. Can't accept my own answer for 2 days? Dunno I'm a stack noob. Thanks to people that helped.
I fixed it, its not pretty but it works. An array of booleans to keep track if the value have been used already. And not actaully adding/removing values from the list from within the while-loop (had a few infinite-loops trying out things :S).
bool[,] tileOccupied = new bool[maxX, maxZ];
for (int i = 0; i < myPlayer.myPlayerUnits.Count; i++)
{
int tileValue = UnityEngine.Random.Range(0, myPlayer.mySpawnArea.Count);
int[,] spawnTile = myPlayer.mySpawnArea[tileValue];
if (tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] == true)
{
do
{
tileValue = UnityEngine.Random.Range(0, myPlayer.mySpawnArea.Count - 1);
spawnTile = myPlayer.mySpawnArea[tileValue];
} while (tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] == true);
}
tileOccupied[spawnTile.GetLength(0), spawnTile.GetLength(1)] = true;
spawnPositions.Add(spawnTile);
}
When I try run the aplication, it shows the Index was outside the bounds of the array at line float[] u_f = a[userid];
Any idea?
PS. the user ID can be every integer,but I take the index of the integer with is between(0, 1143600 for item) and (0, 89395 for user) and my calculation is based on that.Then, my calculation is based on the index of userid value which is stored in array a not based on the value of userid.
Thanks in advance
float[][] a = Enumerable.Range(0, 89395).Select(i => new float[100]).ToArray();
float[][] b = Enumerable.Range(0, 1143600).Select(j => new float[100]).ToArray();
int[] c = new int[1258038];
int[] d = new int [92160];
........
public float dotproduct(int userid, int itemid)
{
result = 0f;
float[] u_f = a[userid]; // <----Error Line (index was outside the bounds of array)
float[] i_f = b[itemid];
for (int i = 0; i < u_f.Length; i++)
{
result += u_f[i] * i_f[i];
}
return result;
}
private void btn_recomm_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(txtbx_id.Text) && String.IsNullOrEmpty(txtbx_itemid.Text) && !String.IsNullOrEmpty(txtbx_noofrecomm.Text))
{
int sc = Convert.ToInt32(txtbx_id.Text);
int n = Convert.ToInt32(txtbx_noofrecomm.Text);
int userseq=Array.IndexOf(d, sc);
var results = new List<float>(1143600);
for (int z = 0; z <= 1143600; z++)
{
results.Add(dotproduct(userseq, z));
}
var sb1 = new StringBuilder();
foreach (var resultwithindex in results.Select((r, index) => new { result = r, Index = index }).OrderByDescending(r => r.result).Take(n))
{
sb1.AppendFormat("{0}: {1}", d[resultwithindex.Index], resultwithindex.result);
sb1.AppendLine();
}
MessageBox.Show(sb1.ToString());
}
if (!String.IsNullOrEmpty(txtbx_id.Text) && !String.IsNullOrEmpty(txtbx_itemid.Text) && String.IsNullOrEmpty(txtbx_noofrecomm.Text))
{
int uid = Convert.ToInt32(txtbx_id.Text);
int iid = Convert.ToInt32(txtbx_itemid.Text);
int userseq0 = Array.IndexOf(d, uid);
int itemseq0 = Array.IndexOf(c, iid);
dotproduct(userseq0, itemseq0);
MessageBox.Show("The Score of item id " + itemseq0 + " is " + result);
}
It means the value of userID is higher than the maximum index number of the array a. The maximum index is count - 1.
The error message mentions that.
Also, it looks like a is two dimensional. Could this be your problem?
Obviously dotproduct gets called with userid value being equal to or greater than a.Length.
If that's not supposed to happen then add this line before declaring u_f array:
Debug.Assert(a.Length > userid);
Of course this won't solve the problem in itself but it will ensure you that whenever such a situation happens while you are testing, it won't go unnoticed or swallowed.
As a side note, clearer variable names would make it easier on you to read your code and figure out issues. Using actual types instead of jagged arrays would likely help too, if possible.
replace a[userid] with
a[userid-1]
int i;
int [,] Prices = new int [2, 7]{{1,2,3,4,5,6,7},{700,600,500,400,300,200,100}};
string[,] City = new string [2,1]{{"A"},{"B"}};
bool found = false;
for (i = 0; i <= City.Length -1; i++)
// for (y = 0; y <= City.Length - 1; y++)
{
if (LstDestinationCity.Text == City[i]) <<-- i get error here
{
im planing to do a program that if i select A city i get first row if B city i get 2 row
I think that's because City[i] "don't contain anything" you should check City[i,0]
if (LstDestinationCity.Text == City[i,0])// this should access the first element which is the text you are looking for
I would rather do it as
if (LstDestinationCity.Text == City[i,i])
{
// ...
}
Your City variable does not need to be a two dimensional array. If you change it to a one dimensional array you can access the values with one index instead of 2.
string[] City = new string [2]{"A","B"};
I have the following foreach loop in C#:
foreach(var item in mod)
{
int i;
i = i + 1;
if (i % 2 == 0)
{
string y = "even number";
}
}
How come I get the message that local variable is unassigned. I am trying to find the even number here.
To resolve the message you are getting, you simply need to initialize it:
int i = 0;
If your intention is to count every item, then you will also need to change the scope of i to outside of the foreach. Otherwise, as you originally posted, the variable i will have the same value for every iteration of the loop.
See this code snippet for both the initialization and scope change:
int i = 0;
foreach (var item in mod)
{
i = i + 1; // is the first item considered even or odd? that answer changes where this should go
if (i % 2 == 0) {
string y = "even number";
}
}
You need to initialise your i variable:
int i = 0;
You're currently trying + 1 to an unassigned variable.
You get the warning because you are not assigning i before using it in i = i + 1. You want to declare i outside of your foreach loop, so you it isn't bound to the scope of the loop. Then initialize with 0 and use the increment feature. Something like:
int i = 0;
foreach (var item in mod)
{
i++;
if (i % 2 == 0)
{
string y = "even number";
}
}
An alternative to what others have suggested here (although correct) would be to use a for loop, this would take care of i for you, e.g.
for (int i = 0; i < mod.length; i++)
{
if (i % 2 == 0)
{
string y = "even number";
}
}
Change this: int i;
to this: int i = 0;
Values types in C# like int do have default values, but you're still not allowed to use an unassigned value-type variable.
You need to assign an initial value for i before you can do i=i+1
You have to initialize i. Right now the compiler is reading this as i = garbage in memory. So you have garbage in memory = garbage in memory + 1. That i could be equal to a string, a number, or anything.
int i = 0;
In addition, you need to initialize that variable outside of the for...each loop, or it will keep resetting itself to 0.
int i = 0;
foreach(var item in mod){
i = i + 1;
if (i % 2 == 0) {
string y = "even number";
}
}
int i = 0;
foreach(var item in mod)
{
if (i % 2 == 0)
{
string y = "even number";
}
i = i + 1;
}
//what are you doing with y and how are you returning y if you need it..
are you expecting to break out at some point.. ? what if item has zero items..??
I have an array of integers and need to find the position in the array of the maximum number along with the minimum. I have it working but it doesn't seem to be a very good way to do it. Can anyone suggest a better way to achieve what I have?
Here's my code:
int[] usageHours = { 3, 3, 5, 4, 0, 0, 2, 2, 4, 25, 158, 320, 212, 356, 401, 460, 480, 403, 298, 213, 102, 87, 34, 45 };
double myAverage = usageHours.Average();
int runningTotal = 0;
int runningMaxPosition = 0;
for (int i = 0; i < usageHours.Length; i++)
{
if (usageHours[i] > runningTotal)
{
runningMaxPosition = i;
runningTotal = usageHours[i];
}
}
txtmax.Text = Convert.ToString(runningMaxPosition)+" With: "+Convert.ToString(runningTotal)+" Users";
txtAv.Text = Convert.ToString(myAverage);
That code is mostly fine. I'd suggest changing the variable names a bit, but that's all. You can work out the minimum in the same loop. I've changed the "if" conditions very slightly to guarantee that they always pick out at least one element (even if all the values are, say, int.MinValue). There are other ways of approaching this, but this is one example. If you have an empty array, you'll end up with max=min=0, and both indexes=-1.
int currentMax = 0;
int currentMaxIndex = -1;
int currentMin = 0;
int currentMinIndex = -1;
for (int i = 0; i < usageHours.Length; i++)
{
if (currentMaxIndex == -1 || usageHours[i] > currentMax)
{
currentMaxIndex = i;
currentMax = usageHours[i];
}
if (currentMinIndex == -1 || usageHours[i] < currentMin)
{
currentMinIndex = i;
currentMin = usageHours[i];
}
}
Here's an alternative using nullable value types to represent "there were no values" answers:
int currentMax? = null;
int currentMaxIndex? = null;
int currentMin? = null;
int currentMinIndex? = null;
for (int i = 0; i < usageHours.Length; i++)
{
if (currentMax == null || usageHours[i] > currentMax.Value)
{
currentMax = i;
currentMax = usageHours[i];
}
if (currentMin == null || usageHours[i] < currentMin.Value)
{
currentMinIndex = i;
currentMin = usageHours[i];
}
}
Don't worry if you haven't come across nullable value types yet though...
The code looks OK for finding the max value. If you are using C# 3 or later you could use the LINQ extension methods (there are Min, Max and Average methods, and on List there is also a FindIndex method, amongst others), but I get the impression that you are learning programming, and then it is sometimes a good idea to implement stuff that may be built into the framework, just for the learning value.
I just wanted to provide one-liner solution for the question (for completeness).
In the OP's original question he only asks for index of the maximum and index of the minimum.
Let's stick to this question. This is the most interesting question because to find maximum value we can simply use Enumerable.Max LINQ method. The same goes for Min and Average.
Let's only provide index of the max, index of min can be retrieved with similar code.
int indexOfMax = Enumerable.Range(0, usageHours.Length).Aggregate(
(indexOfMax, i) => (usageHours[i] > usageHours[indexOfMax] ? i : indexOfMax)
);
Delegate inside of Aggregate's brackets is executed for each index of array. It gets as parameters "index of maximum value so far found", and current index. It returns "index of maximum value so far found". Obviously in each iteration "index of maximum value so far found" will only change to current index if corresponding element of array is greater than previous maximum.
scratch the linq code, it didnt work the way you wanted
you could make your code a little bit more concise
for (int i = 0; i < usageHours.Length; i++)
{
if (usageHours[i] > usageHours[runningMaxPosition])
runningMaxPosition = i;
}
all it does differently is leavs out the temporary runningTotal variable.
How about this:
double average = usageHours.Average();
int maxPosition = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int minPosition = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);
Your code isn't bad, but it won't work if all the values are less than zero.
Try this:
int getArrayMaxPosition (double[] theArray)
{
double maxVal = theArray[0];
int ret = 0;
int currentIndex = 0;
foreach (double aValue in theArray)
{
if (aValue > maxVal)
{
ret = currentIndex;
maxVal = avalue;
}
currentIndex++;
}
return ret;
}
As was mentioned on the comment's to Jon's answer, Jon's solution really is the best, most direct, quickest way of doing it.
If, however, you did want to use Igor's solution, here's the rest of it (to get the actual positions as well as the values):
int maxValue = Enumerable.Range(0, usageHours.Length).Max(i => usageHours[i]);
int maxPosition = Array.FindIndex(usageHours, i => i == maxValue);
int minValue = Enumerable.Range(0, usageHours.Length).Min(i => usageHours[i]);
int minPosition = Array.FindIndex(usageHours, i => i == minValue);